Merge "Add setting to go to sleep after long user inactivity"
diff --git a/Android.bp b/Android.bp
index 190649a..5070b5e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -405,6 +405,8 @@
 filegroup {
     name: "statsd_aidl",
     srcs: [
+        "core/java/android/os/IPullAtomCallback.aidl",
+        "core/java/android/os/IPullAtomResultReceiver.aidl",
         "core/java/android/os/IStatsCompanionService.aidl",
         "core/java/android/os/IStatsManager.aidl",
         "core/java/android/os/IStatsPullerCallback.aidl",
@@ -425,6 +427,7 @@
     name: "framework-minus-apex",
     defaults: ["framework-defaults"],
     srcs: [":framework-non-updatable-sources"],
+    libs: ["app-compat-annotations"],
     installable: true,
     javac_shard_size: 150,
     required: [
@@ -463,12 +466,14 @@
     defaults: ["framework-defaults"],
     srcs: [":framework-all-sources"],
     installable: false,
+    libs: ["app-compat-annotations"],
 }
 
 java_library {
     name: "framework-annotation-proc",
     defaults: ["framework-aidl-export-defaults"],
     srcs: [":framework-all-sources"],
+    libs: ["app-compat-annotations"],
     installable: false,
     plugins: [
         "unsupportedappusage-annotation-processor",
@@ -509,6 +514,7 @@
 java_library {
     name: "framework-atb-backward-compatibility",
     installable: true,
+    libs: ["app-compat-annotations"],
     srcs: [
         "core/java/android/content/pm/AndroidTestBaseUpdater.java",
     ],
@@ -760,6 +766,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 +1014,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",
@@ -1022,7 +1053,6 @@
     previous_api: ":last-released-public-api-for-metalava-annotations",
     merge_annotations_dirs: [
         "metalava-manual",
-        "ojluni-annotated-sdk-stubs",
     ],
 }
 
@@ -1079,7 +1109,6 @@
     previous_api: ":last-released-public-api-for-metalava-annotations",
     merge_annotations_dirs: [
         "metalava-manual",
-        "ojluni-annotated-sdk-stubs",
     ],
     api_levels_annotations_enabled: true,
     api_levels_annotations_dirs: [
@@ -1414,7 +1443,6 @@
     previous_api: ":last-released-public-api-for-metalava-annotations",
     merge_annotations_dirs: [
         "metalava-manual",
-        "ojluni-annotated-sdk-stubs",
     ],
     args: " --show-annotation android.annotation.SystemApi",
 }
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..0a4e020 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerService.java
@@ -2697,7 +2697,6 @@
                     args);
         }
 
-
         /**
          * <b>For internal system user only!</b>
          * Returns a list of all currently-executing jobs.
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..a0615aa 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;
 
@@ -76,6 +76,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
+import android.os.IPullAtomCallback;
 import android.os.IStatsCompanionService;
 import android.os.IStatsManager;
 import android.os.IStoraged;
@@ -144,6 +145,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 +166,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
@@ -216,7 +221,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 +244,7 @@
             "/system/bin/traced_probes",  // Perfetto.
             "webview_zygote",
             "zygote",
-            "zygote64",
-    };
+            "zygote64");
     /**
      * Lowest available uid for apps.
      *
@@ -270,6 +274,72 @@
     private final BroadcastReceiver mAppUpdateReceiver;
     private final BroadcastReceiver mUserUpdateReceiver;
     private final ShutdownEventReceiver mShutdownEventReceiver;
+
+    private static final class PullerKey {
+        private final int mUid;
+        private final int mAtomTag;
+
+        PullerKey(int uid, int atom) {
+            mUid = uid;
+            mAtomTag = atom;
+        }
+
+        public int getUid() {
+            return mUid;
+        }
+
+        public int getAtom() {
+            return mAtomTag;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mUid, mAtomTag);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof PullerKey) {
+                PullerKey other = (PullerKey) obj;
+                return this.mUid == other.getUid() && this.mAtomTag == other.getAtom();
+            }
+            return false;
+        }
+    }
+
+    private static final class PullerValue {
+        private final long mCoolDownNs;
+        private final long mTimeoutNs;
+        private int[] mAdditiveFields;
+        private IPullAtomCallback mCallback;
+
+        PullerValue(long coolDownNs, long timeoutNs, int[] additiveFields,
+                IPullAtomCallback callback) {
+            mCoolDownNs = coolDownNs;
+            mTimeoutNs = timeoutNs;
+            mAdditiveFields = additiveFields;
+            mCallback = callback;
+        }
+
+        public long getCoolDownNs() {
+            return mCoolDownNs;
+        }
+
+        public long getTimeoutNs() {
+            return mTimeoutNs;
+        }
+
+        public int[] getAdditiveFields() {
+            return mAdditiveFields;
+        }
+
+        public IPullAtomCallback getCallback() {
+            return mCallback;
+        }
+    }
+
+    private final HashMap<PullerKey, PullerValue> mPullers = new HashMap<>();
+
     private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
     private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
     private IWifiManager mWifiManager = null;
@@ -321,7 +391,6 @@
             @Override
             public void onReceive(Context context, Intent intent) {
                 synchronized (sStatsdLock) {
-                    sStatsd = fetchStatsdService();
                     if (sStatsd == null) {
                         Slog.w(TAG, "Could not access statsd for UserUpdateReceiver");
                         return;
@@ -1220,27 +1289,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 +1337,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 +1361,7 @@
             e.writeInt(snapshot.swapInKilobytes);
             e.writeInt(snapshot.anonRssInKilobytes + snapshot.swapInKilobytes);
             pulledData.add(e);
-        }
+        });
     }
 
     private static boolean isAppUid(int uid) {
@@ -2549,10 +2620,40 @@
         mContext.enforceCallingPermission(android.Manifest.permission.STATSCOMPANION, null);
     }
 
+    @Override
+    public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+            int[] additiveFields, IPullAtomCallback pullerCallback) {
+        synchronized (sStatsdLock) {
+            // Always cache the puller in SCS.
+            // If statsd is down, we will register it when it comes back up.
+            int callingUid = Binder.getCallingUid();
+            final long token = Binder.clearCallingIdentity();
+            PullerKey key = new PullerKey(callingUid, atomTag);
+            PullerValue val = new PullerValue(
+                    coolDownNs, timeoutNs, additiveFields, pullerCallback);
+            mPullers.put(key, val);
+
+            if (sStatsd == null) {
+                Slog.w(TAG, "Could not access statsd for registering puller for atom " + atomTag);
+                return;
+            }
+            try {
+                sStatsd.registerPullAtomCallback(
+                        callingUid, atomTag, coolDownNs, timeoutNs, additiveFields, pullerCallback);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to access statsd to register puller for atom " + atomTag);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+    }
+
     // Lifecycle and related code
 
     /**
-     * Fetches the statsd IBinder service
+     * Fetches the statsd IBinder service.
+     * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
+     * sStatsd with a null check.
      */
     private static IStatsManager fetchStatsdService() {
         return IStatsManager.Stub.asInterface(ServiceManager.getService("stats"));
@@ -2650,6 +2751,8 @@
                     // Pull the latest state of UID->app name, version mapping when
                     // statsd starts.
                     informAllUidsLocked(mContext);
+                    // Register all pullers. If SCS has just started, this should be empty.
+                    registerAllPullersLocked();
                 } finally {
                     restoreCallingIdentity(token);
                 }
@@ -2661,10 +2764,21 @@
         }
     }
 
+    @GuardedBy("sStatsdLock")
+    private void registerAllPullersLocked() throws RemoteException {
+        // TODO: pass in one call, using a file descriptor (similar to uidmap).
+        for (Map.Entry<PullerKey, PullerValue> entry : mPullers.entrySet()) {
+            PullerKey key = entry.getKey();
+            PullerValue val = entry.getValue();
+            sStatsd.registerPullAtomCallback(key.getUid(), key.getAtom(), val.getCoolDownNs(),
+                    val.getTimeoutNs(), val.getAdditiveFields(), val.getCallback());
+        }
+    }
+
     private class StatsdDeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
-            Slog.i(TAG, "Statsd is dead - erase all my knowledge.");
+            Slog.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
             synchronized (sStatsdLock) {
                 long now = SystemClock.elapsedRealtime();
                 for (Long timeMillis : mDeathTimeMillis) {
diff --git a/api/current.txt b/api/current.txt
index fdd30db..b1423b4 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
@@ -1609,7 +1609,7 @@
     field public static final int windowShowWallpaper = 16843410; // 0x1010292
     field public static final int windowSoftInputMode = 16843307; // 0x101022b
     field public static final int windowSplashscreenContent = 16844132; // 0x1010564
-    field public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
+    field @Deprecated public static final int windowSwipeToDismiss = 16843763; // 0x10103f3
     field public static final int windowTitleBackgroundStyle = 16842844; // 0x101005c
     field public static final int windowTitleSize = 16842842; // 0x101005a
     field public static final int windowTitleStyle = 16842843; // 0x101005b
@@ -1873,6 +1873,15 @@
     field public static final int accessibilityActionSetProgress = 16908349; // 0x102003d
     field public static final int accessibilityActionShowOnScreen = 16908342; // 0x1020036
     field public static final int accessibilityActionShowTooltip = 16908356; // 0x1020044
+    field public static final int accessibilitySystemActionBack = 16908363; // 0x102004b
+    field public static final int accessibilitySystemActionHome = 16908364; // 0x102004c
+    field public static final int accessibilitySystemActionLockScreen = 16908370; // 0x1020052
+    field public static final int accessibilitySystemActionNotifications = 16908366; // 0x102004e
+    field public static final int accessibilitySystemActionPowerDialog = 16908368; // 0x1020050
+    field public static final int accessibilitySystemActionQuickSettings = 16908367; // 0x102004f
+    field public static final int accessibilitySystemActionRecents = 16908365; // 0x102004d
+    field public static final int accessibilitySystemActionTakeScreenshot = 16908371; // 0x1020053
+    field public static final int accessibilitySystemActionToggleSplitScreen = 16908369; // 0x1020051
     field public static final int addToDictionary = 16908330; // 0x102002a
     field public static final int autofill = 16908355; // 0x1020043
     field public static final int background = 16908288; // 0x1020000
@@ -2324,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
@@ -9641,8 +9650,9 @@
     method public static boolean isSyncPending(android.accounts.Account, String);
     method @NonNull public android.graphics.Bitmap loadThumbnail(@NonNull android.net.Uri, @NonNull android.util.Size, @Nullable android.os.CancellationSignal) throws java.io.IOException;
     method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
-    method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
+    method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
     method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
+    method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
     method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -15703,6 +15713,8 @@
 
   public final class Icon implements android.os.Parcelable {
     method public static android.graphics.drawable.Icon createWithAdaptiveBitmap(android.graphics.Bitmap);
+    method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull String);
+    method @NonNull public static android.graphics.drawable.Icon createWithAdaptiveBitmapContentUri(@NonNull android.net.Uri);
     method public static android.graphics.drawable.Icon createWithBitmap(android.graphics.Bitmap);
     method public static android.graphics.drawable.Icon createWithContentUri(String);
     method public static android.graphics.drawable.Icon createWithContentUri(android.net.Uri);
@@ -15729,6 +15741,7 @@
     field public static final int TYPE_DATA = 3; // 0x3
     field public static final int TYPE_RESOURCE = 2; // 0x2
     field public static final int TYPE_URI = 4; // 0x4
+    field public static final int TYPE_URI_ADAPTIVE_BITMAP = 6; // 0x6
   }
 
   public static interface Icon.OnDrawableLoadedListener {
@@ -23029,17 +23042,17 @@
   }
 
   public final class GnssStatus {
-    method public float getAzimuthDegrees(int);
-    method public float getCarrierFrequencyHz(int);
-    method public float getCn0DbHz(int);
-    method public int getConstellationType(int);
-    method public float getElevationDegrees(int);
-    method public int getSatelliteCount();
-    method public int getSvid(int);
-    method public boolean hasAlmanacData(int);
-    method public boolean hasCarrierFrequencyHz(int);
-    method public boolean hasEphemerisData(int);
-    method public boolean usedInFix(int);
+    method @FloatRange(from=0, to=360) public float getAzimuthDegrees(@IntRange(from=0) int);
+    method @FloatRange(from=0) public float getCarrierFrequencyHz(@IntRange(from=0) int);
+    method @FloatRange(from=0, to=63) public float getCn0DbHz(@IntRange(from=0) int);
+    method public int getConstellationType(@IntRange(from=0) int);
+    method @FloatRange(from=0xffffffa6, to=90) public float getElevationDegrees(@IntRange(from=0) int);
+    method @IntRange(from=0) public int getSatelliteCount();
+    method @IntRange(from=1, to=200) public int getSvid(@IntRange(from=0) int);
+    method public boolean hasAlmanacData(@IntRange(from=0) int);
+    method public boolean hasCarrierFrequencyHz(@IntRange(from=0) int);
+    method public boolean hasEphemerisData(@IntRange(from=0) int);
+    method public boolean usedInFix(@IntRange(from=0) int);
     field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
     field public static final int CONSTELLATION_GALILEO = 6; // 0x6
     field public static final int CONSTELLATION_GLONASS = 3; // 0x3
@@ -23050,10 +23063,17 @@
     field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
+  public static final class GnssStatus.Builder {
+    ctor public GnssStatus.Builder();
+    method @NonNull public android.location.GnssStatus.Builder addSatellite(int, @IntRange(from=1, to=200) int, @FloatRange(from=0, to=63) float, @FloatRange(from=0xffffffa6, to=90) float, @FloatRange(from=0, to=360) float, boolean, boolean, boolean, boolean, @FloatRange(from=0) float);
+    method @NonNull public android.location.GnssStatus build();
+    method @NonNull public android.location.GnssStatus.Builder clearSatellites();
+  }
+
   public abstract static class GnssStatus.Callback {
     ctor public GnssStatus.Callback();
     method public void onFirstFix(int);
-    method public void onSatelliteStatusChanged(android.location.GnssStatus);
+    method public void onSatelliteStatusChanged(@NonNull android.location.GnssStatus);
     method public void onStarted();
     method public void onStopped();
   }
@@ -23069,6 +23089,7 @@
   }
 
   @Deprecated public final class GpsStatus {
+    method @Deprecated @NonNull public static android.location.GpsStatus create(@NonNull android.location.GnssStatus, int);
     method @Deprecated public int getMaxSatellites();
     method @Deprecated public Iterable<android.location.GpsSatellite> getSatellites();
     method @Deprecated public int getTimeToFirstFix();
@@ -23155,6 +23176,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);
@@ -23185,6 +23207,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);
@@ -23491,6 +23514,7 @@
     method @Deprecated public boolean isBluetoothA2dpOn();
     method public boolean isBluetoothScoAvailableOffCall();
     method public boolean isBluetoothScoOn();
+    method public boolean isCallScreeningModeSupported();
     method public static boolean isHapticPlaybackSupported();
     method public boolean isMicrophoneMute();
     method public boolean isMusicActive();
@@ -23589,6 +23613,7 @@
     field public static final int GET_DEVICES_ALL = 3; // 0x3
     field public static final int GET_DEVICES_INPUTS = 1; // 0x1
     field public static final int GET_DEVICES_OUTPUTS = 2; // 0x2
+    field public static final int MODE_CALL_SCREENING = 4; // 0x4
     field public static final int MODE_CURRENT = -1; // 0xffffffff
     field public static final int MODE_INVALID = -2; // 0xfffffffe
     field public static final int MODE_IN_CALL = 2; // 0x2
@@ -24028,7 +24053,7 @@
     ctor public ExifInterface(@NonNull String) throws java.io.IOException;
     ctor public ExifInterface(@NonNull java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(@NonNull java.io.InputStream) throws java.io.IOException;
-    method @NonNull public static android.media.ExifInterface fromStandalone(@NonNull java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(@NonNull java.io.InputStream, int) throws java.io.IOException;
     method public double getAltitude(double);
     method @Nullable public String getAttribute(@NonNull String);
     method @Nullable public byte[] getAttributeBytes(@NonNull String);
@@ -24055,6 +24080,8 @@
     field public static final int ORIENTATION_TRANSPOSE = 5; // 0x5
     field public static final int ORIENTATION_TRANSVERSE = 7; // 0x7
     field public static final int ORIENTATION_UNDEFINED = 0; // 0x0
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field @Deprecated public static final String TAG_APERTURE = "FNumber";
     field public static final String TAG_APERTURE_VALUE = "ApertureValue";
     field public static final String TAG_ARTIST = "Artist";
@@ -24140,6 +24167,9 @@
     field public static final String TAG_MODEL = "Model";
     field public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
     field public static final String TAG_OECF = "OECF";
+    field public static final String TAG_OFFSET_TIME = "OffsetTime";
+    field public static final String TAG_OFFSET_TIME_DIGITIZED = "OffsetTimeDigitized";
+    field public static final String TAG_OFFSET_TIME_ORIGINAL = "OffsetTimeOriginal";
     field public static final String TAG_ORF_ASPECT_FRAME = "AspectFrame";
     field public static final String TAG_ORF_PREVIEW_IMAGE_LENGTH = "PreviewImageLength";
     field public static final String TAG_ORF_PREVIEW_IMAGE_START = "PreviewImageStart";
@@ -30343,6 +30373,7 @@
   public static final class WifiAwareNetworkSpecifier.Builder {
     ctor public WifiAwareNetworkSpecifier.Builder(@NonNull android.net.wifi.aware.DiscoverySession, @NonNull android.net.wifi.aware.PeerHandle);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
+    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(@IntRange(from=0, to=65535) int);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
     method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(@IntRange(from=0, to=255) int);
@@ -35342,6 +35373,8 @@
   public class RemoteException extends android.util.AndroidException {
     ctor public RemoteException();
     ctor public RemoteException(String);
+    method @NonNull public RuntimeException rethrowAsRuntimeException();
+    method @NonNull public RuntimeException rethrowFromSystemServer();
   }
 
   public class ResultReceiver implements android.os.Parcelable {
@@ -37122,6 +37155,7 @@
     field public static final String DURATION = "duration";
     field public static final String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final String FEATURES = "features";
+    field public static final int FEATURES_ASSISTED_DIALING_USED = 16; // 0x10
     field public static final int FEATURES_HD_CALL = 4; // 0x4
     field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_RTT = 32; // 0x20
@@ -38948,6 +38982,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";
@@ -38987,6 +39022,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";
@@ -43394,6 +43430,7 @@
     field public static final int DIRECTION_INCOMING = 0; // 0x0
     field public static final int DIRECTION_OUTGOING = 1; // 0x1
     field public static final int DIRECTION_UNKNOWN = -1; // 0xffffffff
+    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
     field public static final int PROPERTY_CONFERENCE = 1; // 0x1
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
@@ -43507,6 +43544,7 @@
     method public final void removeConnection(android.telecom.Connection);
     method public final void removeExtras(java.util.List<java.lang.String>);
     method public final void removeExtras(java.lang.String...);
+    method public void sendConferenceEvent(@NonNull String, @Nullable android.os.Bundle);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
@@ -43646,6 +43684,7 @@
     field public static final String EXTRA_IS_RTT_AUDIO_PRESENT = "android.telecom.extra.IS_RTT_AUDIO_PRESENT";
     field public static final String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
     field public static final String EXTRA_SIP_INVITE = "android.telecom.extra.SIP_INVITE";
+    field public static final int PROPERTY_ASSISTED_DIALING_USED = 512; // 0x200
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 4; // 0x4
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
@@ -44060,6 +44099,7 @@
     method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
     method public android.telecom.PhoneAccountHandle getSimCallManager();
+    method @Nullable public android.telecom.PhoneAccountHandle getSimCallManagerForSubscription(int);
     method @Nullable public String getSystemDialerPackage();
     method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
@@ -44108,6 +44148,7 @@
     field public static final String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
     field public static final String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
     field public static final String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
+    field public static final String EXTRA_USE_ASSISTED_DIALING = "android.telecom.extra.USE_ASSISTED_DIALING";
     field public static final String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
     field public static final String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
@@ -45203,6 +45244,7 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
     method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
     method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
+    method public static int getActiveDataSubscriptionId();
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
     method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount();
     method public int getActiveSubscriptionInfoCountMax();
@@ -45339,8 +45381,8 @@
     method @Nullable public CharSequence getSimSpecificCarrierIdName();
     method public int getSimState();
     method public int getSimState(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubIdForPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getSubscriberId();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getSubscriptionId(@NonNull android.telecom.PhoneAccountHandle);
     method public int getSupportedModemCount();
     method @Nullable public String getTypeAllocationCode();
     method @Nullable public String getTypeAllocationCode(int);
@@ -45753,11 +45795,13 @@
     method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
     field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
     field public static final String ACTION_NOTIFY_CARRIER_SETUP_INCOMPLETE = "android.telephony.euicc.action.NOTIFY_CARRIER_SETUP_INCOMPLETE";
+    field public static final String ACTION_START_EUICC_ACTIVATION = "android.telephony.euicc.action.START_EUICC_ACTIVATION";
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_ERROR = 2; // 0x2
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
     field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
     field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
     field public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
+    field public static final String EXTRA_USE_QR_SCANNER = "android.telephony.euicc.extra.USE_QR_SCANNER";
     field public static final String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
   }
 
@@ -52078,7 +52122,7 @@
     field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
     field @Deprecated public static final int FEATURE_PROGRESS = 2; // 0x2
     field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
-    field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
+    field @Deprecated public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
     field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
     field public static final String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "android:navigation:background";
     field @Deprecated public static final int PROGRESS_END = 10000; // 0x2710
@@ -52255,7 +52299,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 a395cc7..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 {
@@ -516,10 +511,6 @@
     field public static final String VOLUME_VOICE = "volume_voice";
   }
 
-  public static final class Telephony.Sms.Intents {
-    field public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
-  }
-
 }
 
 package android.speech.tts {
diff --git a/api/system-current.txt b/api/system-current.txt
index b3610f5..62ab6d6 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -261,6 +261,8 @@
   public static final class R.string {
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
     field public static final int config_defaultBrowser = 17039394; // 0x1040022
+    field public static final int config_defaultCallRedirection = 17039400; // 0x1040028
+    field public static final int config_defaultCallScreening = 17039401; // 0x1040029
     field public static final int config_defaultDialer = 17039395; // 0x1040023
     field public static final int config_defaultSms = 17039396; // 0x1040024
     field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
@@ -1389,6 +1391,10 @@
 
 package android.content {
 
+  public abstract class BroadcastReceiver {
+    method @NonNull public final android.os.UserHandle getSendingUser();
+  }
+
   public class ContentProviderClient implements java.lang.AutoCloseable {
     method @RequiresPermission(android.Manifest.permission.REMOVE_TASKS) public void setDetectNotResponding(long);
   }
@@ -1405,8 +1411,10 @@
     method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract java.io.File getPreloadsFileCache();
     method public abstract boolean isCredentialProtectedStorage();
+    method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public android.content.Intent registerReceiverForAllUsers(@Nullable android.content.BroadcastReceiver, @NonNull android.content.IntentFilter, @Nullable String, @Nullable android.os.Handler);
     method public abstract void sendBroadcast(android.content.Intent, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public abstract void sendBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, @Nullable android.os.Bundle);
+    method public void sendBroadcastMultiplePermissions(@NonNull android.content.Intent, @NonNull String[]);
     method public abstract void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable android.os.Bundle, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public void startActivityAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.os.UserHandle);
     field public static final String APP_PREDICTION_SERVICE = "app_prediction";
@@ -4838,6 +4846,7 @@
     method public boolean isPortableHotspotSupported();
     method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public boolean isWifiApEnabled();
     method public boolean isWifiScannerSupported();
+    method @RequiresPermission("android.permission.NETWORK_SETTINGS") public void registerSoftApCallback(@NonNull android.net.wifi.WifiManager.SoftApCallback, @Nullable java.util.concurrent.Executor);
     method @RequiresPermission("android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE") public void removeOnWifiUsabilityStatsListener(@NonNull android.net.wifi.WifiManager.OnWifiUsabilityStatsListener);
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void save(@NonNull android.net.wifi.WifiConfiguration, @Nullable android.net.wifi.WifiManager.ActionListener);
     method @RequiresPermission("android.permission.WIFI_SET_DEVICE_MOBILITY_STATE") public void setDeviceMobilityState(int);
@@ -4897,6 +4906,12 @@
     method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
   }
 
+  public static interface WifiManager.SoftApCallback {
+    method public void onConnectedClientsChanged(@NonNull java.util.List<android.net.wifi.WifiClient>);
+    method public default void onInfoChanged(@NonNull android.net.wifi.SoftApInfo);
+    method public void onStateChanged(int, int);
+  }
+
   public class WifiNetworkConnectionStatistics implements android.os.Parcelable {
     ctor public WifiNetworkConnectionStatistics(int, int);
     ctor public WifiNetworkConnectionStatistics();
@@ -5077,10 +5092,6 @@
     method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
   }
 
-  public static final class WifiAwareNetworkSpecifier.Builder {
-    method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]);
-  }
-
   public class WifiAwareSession implements java.lang.AutoCloseable {
     method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, @NonNull byte[], @NonNull byte[]);
   }
@@ -6299,6 +6310,32 @@
     field public static final int VOLUME_HUSH_VIBRATE = 1; // 0x1
   }
 
+  public static interface Telephony.CarrierColumns extends android.provider.BaseColumns {
+    field @NonNull public static final android.net.Uri CONTENT_URI;
+    field public static final String EXPIRATION_TIME = "expiration_time";
+    field public static final String KEY_IDENTIFIER = "key_identifier";
+    field public static final String KEY_TYPE = "key_type";
+    field public static final String LAST_MODIFIED = "last_modified";
+    field public static final String MCC = "mcc";
+    field public static final String MNC = "mnc";
+    field public static final String MVNO_MATCH_DATA = "mvno_match_data";
+    field public static final String MVNO_TYPE = "mvno_type";
+    field public static final String PUBLIC_KEY = "public_key";
+  }
+
+  public static final class Telephony.CarrierId.All implements android.provider.BaseColumns {
+    field public static final String APN = "apn";
+    field @NonNull public static final android.net.Uri CONTENT_URI;
+    field public static final String GID1 = "gid1";
+    field public static final String GID2 = "gid2";
+    field public static final String ICCID_PREFIX = "iccid_prefix";
+    field public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+    field public static final String MCCMNC = "mccmnc";
+    field public static final String PLMN = "plmn";
+    field public static final String PRIVILEGE_ACCESS_RULE = "privilege_access_rule";
+    field public static final String SPN = "spn";
+  }
+
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final String APN_SET_ID = "apn_set_id";
     field public static final int CARRIER_EDITED = 4; // 0x4
@@ -6346,6 +6383,10 @@
     field public static final String SLOT_INDEX = "slot_index";
   }
 
+  public static final class Telephony.Sms.Intents {
+    field public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED = "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
+  }
+
   public final class TimeZoneRulesDataContract {
     field public static final String AUTHORITY = "com.android.timezone";
   }
@@ -6366,6 +6407,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
@@ -6379,6 +6424,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 {
@@ -6768,7 +6817,7 @@
     method public android.service.euicc.DownloadSubscriptionResult onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean, @Nullable android.os.Bundle);
     method @Deprecated public int onDownloadSubscription(int, @NonNull android.telephony.euicc.DownloadableSubscription, boolean, boolean);
     method @Deprecated public abstract int onEraseSubscriptions(int);
-    method public int onEraseSubscriptionsWithOptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
+    method public int onEraseSubscriptions(int, @android.telephony.euicc.EuiccCardManager.ResetOption int);
     method public abstract android.service.euicc.GetDefaultDownloadableSubscriptionListResult onGetDefaultDownloadableSubscriptionList(int, boolean);
     method public abstract android.service.euicc.GetDownloadableSubscriptionMetadataResult onGetDownloadableSubscriptionMetadata(int, android.telephony.euicc.DownloadableSubscription, boolean);
     method public abstract String onGetEid(int);
@@ -6788,6 +6837,8 @@
     field public static final String ACTION_RESOLVE_DEACTIVATE_SIM = "android.service.euicc.action.RESOLVE_DEACTIVATE_SIM";
     field public static final String ACTION_RESOLVE_NO_PRIVILEGES = "android.service.euicc.action.RESOLVE_NO_PRIVILEGES";
     field public static final String ACTION_RESOLVE_RESOLVABLE_ERRORS = "android.service.euicc.action.RESOLVE_RESOLVABLE_ERRORS";
+    field public static final String ACTION_START_CARRIER_ACTIVATION = "android.service.euicc.action.START_CARRIER_ACTIVATION";
+    field public static final String ACTION_START_EUICC_ACTIVATION = "android.service.euicc.action.START_EUICC_ACTIVATION";
     field public static final String ACTION_TOGGLE_SUBSCRIPTION_PRIVILEGED = "android.service.euicc.action.TOGGLE_SUBSCRIPTION_PRIVILEGED";
     field public static final String CATEGORY_EUICC_UI = "android.service.euicc.category.EUICC_UI";
     field public static final String EUICC_SERVICE_INTERFACE = "android.service.euicc.EuiccService";
@@ -7199,14 +7250,18 @@
   public abstract class Conference extends android.telecom.Conferenceable {
     method @Deprecated public final android.telecom.AudioState getAudioState();
     method @Deprecated public final long getConnectTimeMillis();
+    method public final long getConnectionStartElapsedRealTime();
     method public android.telecom.Connection getPrimaryConnection();
+    method @NonNull public final String getTelecomCallId();
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
+    method public final void setAddress(@NonNull android.net.Uri, int);
+    method public final void setCallerDisplayName(@NonNull String, int);
+    method public void setConferenceState(boolean);
     method @Deprecated public final void setConnectTimeMillis(long);
   }
 
   public abstract class Connection extends android.telecom.Conferenceable {
     method @Deprecated public final android.telecom.AudioState getAudioState();
-    method public final int getCallRadioTech();
     method public final long getConnectElapsedTimeMillis();
     method public final long getConnectTimeMillis();
     method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
@@ -7214,7 +7269,6 @@
     method @Deprecated public void onAudioStateChanged(android.telecom.AudioState);
     method public final void resetConnectionTime();
     method public void setCallDirection(int);
-    method public final void setCallRadioTech(int);
     method public final void setConnectTimeMillis(long);
     method public final void setConnectionStartElapsedRealTime(long);
     method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
@@ -7228,6 +7282,10 @@
     field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
   }
 
+  public abstract class ConnectionService extends android.app.Service {
+    method public final void addExistingConnection(@NonNull android.telecom.PhoneAccountHandle, @NonNull android.telecom.Connection, @NonNull android.telecom.Conference);
+  }
+
   public abstract class InCallService extends android.app.Service {
     method @Deprecated public android.telecom.Phone getPhone();
     method @Deprecated public void onPhoneCreated(android.telecom.Phone);
@@ -7359,6 +7417,10 @@
     field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
   }
 
+  public static class PhoneAccount.Builder {
+    method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
+  }
+
   public class PhoneAccountSuggestionService extends android.app.Service {
     ctor public PhoneAccountSuggestionService();
     method public void onAccountSuggestionRequest(@NonNull String);
@@ -7430,6 +7492,7 @@
     method public int getCallState();
     method public android.telecom.PhoneAccountHandle getConnectionManager();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCurrentTtyMode();
+    method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultDialerPackage(int);
     method @Deprecated public android.content.ComponentName getDefaultPhoneApp();
     method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage();
     method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
@@ -7901,6 +7964,7 @@
   public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
+    method public boolean isUsingCarrierAggregation();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
   }
@@ -8039,6 +8103,7 @@
     method @Nullable public android.telephony.CellIdentity getCellIdentity();
     method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo();
     method public int getDomain();
+    method public int getNrState();
     method public int getRegistrationState();
     method public int getRejectCause();
     method public int getRoamingType();
@@ -8281,6 +8346,9 @@
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
     method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
+    method public int getNrFrequencyRange();
+    method @Nullable public String getOperatorAlphaLongRaw();
+    method @Nullable public String getOperatorAlphaShortRaw();
     field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
     field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
     field public static final int ROAMING_TYPE_NOT_ROAMING = 0; // 0x0
@@ -8371,7 +8439,7 @@
   }
 
   public final class SmsCbMessage implements android.os.Parcelable {
-    ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int);
+    ctor public SmsCbMessage(int, int, int, @NonNull android.telephony.SmsCbLocation, int, @Nullable String, @Nullable String, int, @Nullable android.telephony.SmsCbEtwsInfo, @Nullable android.telephony.SmsCbCmasInfo, int, @Nullable java.util.List<android.telephony.CbGeoUtils.Geometry>, long, int);
     method @NonNull public static android.telephony.SmsCbMessage createFromCursor(@NonNull android.database.Cursor);
     method public int describeContents();
     method @Nullable public android.telephony.SmsCbCmasInfo getCmasWarningInfo();
@@ -8398,6 +8466,7 @@
     field public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; // 0x0
     field public static final int GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; // 0x2
     field public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; // 0x1
+    field public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255; // 0xff
     field public static final int MESSAGE_FORMAT_3GPP = 1; // 0x1
     field public static final int MESSAGE_FORMAT_3GPP2 = 2; // 0x2
     field public static final int MESSAGE_PRIORITY_EMERGENCY = 3; // 0x3
@@ -8884,7 +8953,7 @@
   public class EuiccManager {
     method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void continueOperation(android.content.Intent, android.os.Bundle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptionsWithOptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
+    method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void eraseSubscriptions(@android.telephony.euicc.EuiccCardManager.ResetOption int, @NonNull android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDefaultDownloadableSubscriptionList(android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public void getDownloadableSubscriptionMetadata(android.telephony.euicc.DownloadableSubscription, android.app.PendingIntent);
     method @RequiresPermission(android.Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS) public int getOtaStatus();
@@ -8907,6 +8976,7 @@
     field public static final String EXTRA_ENABLE_SUBSCRIPTION = "android.telephony.euicc.extra.ENABLE_SUBSCRIPTION";
     field public static final String EXTRA_FORCE_PROVISION = "android.telephony.euicc.extra.FORCE_PROVISION";
     field public static final String EXTRA_FROM_SUBSCRIPTION_ID = "android.telephony.euicc.extra.FROM_SUBSCRIPTION_ID";
+    field public static final String EXTRA_PHYSICAL_SLOT_ID = "android.telephony.euicc.extra.PHYSICAL_SLOT_ID";
     field public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.euicc.extra.SUBSCRIPTION_ID";
     field public static final String EXTRA_SUBSCRIPTION_NICKNAME = "android.telephony.euicc.extra.SUBSCRIPTION_NICKNAME";
   }
@@ -9159,7 +9229,7 @@
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting();
diff --git a/api/test-current.txt b/api/test-current.txt
index 7af7e43..44f736c 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -717,6 +717,7 @@
   }
 
   public class Intent implements java.lang.Cloneable android.os.Parcelable {
+    field @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public static final String ACTION_MANAGE_DEFAULT_APP = "android.intent.action.MANAGE_DEFAULT_APP";
     field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED";
     field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME";
   }
@@ -2914,7 +2915,36 @@
   }
 
   public abstract class Conference extends android.telecom.Conferenceable {
+    method public final long getConnectionStartElapsedRealTime();
     method public android.telecom.Connection getPrimaryConnection();
+    method @NonNull public final String getTelecomCallId();
+    method public final void setAddress(@NonNull android.net.Uri, int);
+    method public final void setCallerDisplayName(@NonNull String, int);
+    method public void setConferenceState(boolean);
+  }
+
+  public abstract class Connection extends android.telecom.Conferenceable {
+    method public final long getConnectElapsedTimeMillis();
+    method public final long getConnectTimeMillis();
+    method @Nullable public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+    method @Nullable public final String getTelecomCallId();
+    method public final void resetConnectionTime();
+    method public void setCallDirection(int);
+    method public final void setConnectTimeMillis(long);
+    method public final void setConnectionStartElapsedRealTime(long);
+    method public void setPhoneAccountHandle(@NonNull android.telecom.PhoneAccountHandle);
+    method public void setTelecomCallId(@NonNull String);
+    field public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 2097152; // 0x200000
+    field public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 262144; // 0x40000
+    field public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";
+    field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1; // 0x1
+    field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+    field public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 64; // 0x40
+    field public static final int PROPERTY_REMOTELY_HOSTED = 2048; // 0x800
+  }
+
+  public static class PhoneAccount.Builder {
+    method @NonNull public android.telecom.PhoneAccount.Builder setGroupId(@NonNull String);
   }
 
   public class PhoneAccountSuggestionService extends android.app.Service {
@@ -2927,6 +2957,7 @@
 
   public class TelecomManager {
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
+    method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDefaultDialerPackage(int);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
     field public static final int TTY_MODE_FULL = 1; // 0x1
@@ -3328,7 +3359,7 @@
 
   public class ImsMmTelManager implements android.telephony.ims.RegistrationManager {
     method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int);
-    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.function.Consumer<java.lang.Integer>, @NonNull java.util.concurrent.Executor) throws android.telephony.ims.ImsException;
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException;
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting();
@@ -4498,7 +4529,7 @@
     field public static final int ACCESSIBILITY_TITLE_CHANGED = 33554432; // 0x2000000
     field public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 64; // 0x40
     field public CharSequence accessibilityTitle;
-    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x200, equals=0x200, name="INHERIT_TRANSLUCENT_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x400, equals=0x400, name="KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE_TRANSPARENT"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC")}) public int privateFlags;
+    field @android.view.ViewDebug.ExportedProperty(flagMapping={@android.view.ViewDebug.FlagToString(mask=0x1, equals=0x1, name="FAKE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x2, equals=0x2, name="FORCE_HARDWARE_ACCELERATED"), @android.view.ViewDebug.FlagToString(mask=0x4, equals=0x4, name="WANTS_OFFSET_NOTIFICATIONS"), @android.view.ViewDebug.FlagToString(mask=0x10, equals=0x10, name="SHOW_FOR_ALL_USERS"), @android.view.ViewDebug.FlagToString(mask=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, equals=android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION, name="NO_MOVE_ANIMATION"), @android.view.ViewDebug.FlagToString(mask=0x80, equals=0x80, name="COMPATIBLE_WINDOW"), @android.view.ViewDebug.FlagToString(mask=0x100, equals=0x100, name="SYSTEM_ERROR"), @android.view.ViewDebug.FlagToString(mask=0x400, equals=0x400, name="KEYGUARD"), @android.view.ViewDebug.FlagToString(mask=0x800, equals=0x800, name="DISABLE_WALLPAPER_TOUCH_EVENTS"), @android.view.ViewDebug.FlagToString(mask=0x1000, equals=0x1000, name="FORCE_STATUS_BAR_VISIBLE_TRANSPARENT"), @android.view.ViewDebug.FlagToString(mask=0x2000, equals=0x2000, name="PRESERVE_GEOMETRY"), @android.view.ViewDebug.FlagToString(mask=0x4000, equals=0x4000, name="FORCE_DECOR_VIEW_VISIBILITY"), @android.view.ViewDebug.FlagToString(mask=0x8000, equals=0x8000, name="WILL_NOT_REPLACE_ON_RELAUNCH"), @android.view.ViewDebug.FlagToString(mask=0x10000, equals=0x10000, name="LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME"), @android.view.ViewDebug.FlagToString(mask=0x20000, equals=0x20000, name="FORCE_DRAW_STATUS_BAR_BACKGROUND"), @android.view.ViewDebug.FlagToString(mask=0x40000, equals=0x40000, name="SUSTAINED_PERFORMANCE_MODE"), @android.view.ViewDebug.FlagToString(mask=0x80000, equals=0x80000, name="HIDE_NON_SYSTEM_OVERLAY_WINDOWS"), @android.view.ViewDebug.FlagToString(mask=0x100000, equals=0x100000, name="IS_ROUNDED_CORNERS_OVERLAY"), @android.view.ViewDebug.FlagToString(mask=0x400000, equals=0x400000, name="IS_SCREEN_DECOR"), @android.view.ViewDebug.FlagToString(mask=0x800000, equals=0x800000, name="STATUS_FORCE_SHOW_NAVIGATION"), @android.view.ViewDebug.FlagToString(mask=0x1000000, equals=0x1000000, name="COLOR_SPACE_AGNOSTIC")}) public int privateFlags;
   }
 
   public class WindowlessViewRoot {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 41d546f..22e1d01 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -174,6 +174,8 @@
                 instrument.noWindowAnimation = true;
             } else if (opt.equals("--no-hidden-api-checks")) {
                 instrument.disableHiddenApiChecks = true;
+            } else if (opt.equals("--no-test-api-checks")) {
+                instrument.disableTestApiChecks = true;
             } else if (opt.equals("--no-isolated-storage")) {
                 instrument.disableIsolatedStorage = true;
             } else if (opt.equals("--user")) {
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 4d7b5a7..6afd7c4 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -17,6 +17,7 @@
 package com.android.commands.am;
 
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
 
 import android.app.IActivityManager;
@@ -85,6 +86,7 @@
     String logPath = null;
     public boolean noWindowAnimation = false;
     public boolean disableHiddenApiChecks = false;
+    public boolean disableTestApiChecks = false;
     public boolean disableIsolatedStorage = false;
     public String abi = null;
     public int userId = UserHandle.USER_CURRENT;
@@ -506,6 +508,9 @@
             if (disableHiddenApiChecks) {
                 flags |= INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
             }
+            if (disableTestApiChecks) {
+                flags |= INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+            }
             if (disableIsolatedStorage) {
                 flags |= INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
             }
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/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b665a8b..f072c9c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1289,6 +1289,13 @@
     return Status::ok();
 }
 
+Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
+                                    int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+                                    const sp<android::os::IPullAtomCallback>& pullerCallback) {
+    VLOG("StatsService::registerPuller called.");
+    return Status::ok();
+}
+
 Status StatsService::unregisterPullerCallback(int32_t atomTag, const String16& packageName) {
     ENFORCE_DUMP_AND_USAGE_STATS(packageName);
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 9490948..6d40007 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -180,6 +180,13 @@
         const String16& packageName) override;
 
     /**
+     * Binder call to register a callback function for a pulled atom.
+     */
+    virtual Status registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownNs,
+            int64_t timeoutNs, const std::vector<int32_t>& additiveFields,
+            const sp<android::os::IPullAtomCallback>& pullerCallback) override;
+
+    /**
      * Binder call to unregister any existing callback function for a vendor pulled atom.
      */
     virtual Status unregisterPullerCallback(int32_t atomTag, const String16& packageName) override;
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 0ee156b..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;
@@ -129,6 +127,7 @@
     if (metric.has_dimensions_in_what()) {
         translateFieldMatcher(metric.dimensions_in_what(), &mDimensionsInWhat);
         mContainANYPositionInDimensionsInWhat = HasPositionANY(metric.dimensions_in_what());
+        mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
     }
 
     if (metric.links().size() > 0) {
@@ -142,8 +141,6 @@
         mConditionSliced = true;
     }
 
-    mSliceByPositionALL = HasPositionALL(metric.dimensions_in_what());
-
     int64_t numBucketsForward = calcBucketsForwardCount(startTimeNs);
     mCurrentBucketNum += numBucketsForward;
 
@@ -267,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).
@@ -366,7 +351,7 @@
 // - ConditionTimer tracks changes based on AND of condition and active state.
 void ValueMetricProducer::onActiveStateChangedLocked(const int64_t& eventTimeNs) {
     bool isEventTooLate  = eventTimeNs < mCurrentBucketStartTimeNs;
-    if (ConditionState::kTrue == mCondition && isEventTooLate) {
+    if (isEventTooLate) {
         // Drop bucket because event arrived too late, ie. we are missing data for this bucket.
         invalidateCurrentBucket();
     }
@@ -401,53 +386,61 @@
     ConditionState newCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
     bool isEventTooLate  = eventTimeNs < mCurrentBucketStartTimeNs;
 
-    if (mIsActive) {
-        if (isEventTooLate) {
-            VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
-                 (long long)mCurrentBucketStartTimeNs);
-            StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
-            invalidateCurrentBucket();
-        } else {
-            if (mCondition == ConditionState::kUnknown) {
-                // If the condition was unknown, we mark the bucket as invalid since the bucket will
-                // contain partial data. For instance, the condition change might happen close to
-                // the end of the bucket and we might miss lots of data.
-                //
-                // We still want to pull to set the base.
-                invalidateCurrentBucket();
-            }
-
-            // Pull on condition changes.
-            bool conditionChanged =
-                    (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)
-                    || (mCondition == ConditionState::kFalse &&
-                            newCondition == ConditionState::kTrue);
-            // We do not need to pull when we go from unknown to false.
-            //
-            // We also pull if the condition was already true in order to be able to flush the
-            // bucket at the end if needed.
-            //
-            // onConditionChangedLocked might happen on bucket boundaries if this is called before
-            // #onDataPulled.
-            if (mIsPulled && (conditionChanged || condition)) {
-                pullAndMatchEventsLocked(eventTimeNs, newCondition);
-            }
-
-            // When condition change from true to false, clear diff base but don't
-            // reset other counters as we may accumulate more value in the bucket.
-            if (mUseDiff && mCondition == ConditionState::kTrue
-                    && newCondition == ConditionState::kFalse) {
-                resetBase();
-            }
-        }
+    // If the config is not active, skip the event.
+    if (!mIsActive) {
+        mCondition = isEventTooLate ? ConditionState::kUnknown : newCondition;
+        return;
     }
 
-    mCondition = isEventTooLate ? initialCondition(mConditionTrackerIndex) : newCondition;
-
-    if (mIsActive) {
-        flushIfNeededLocked(eventTimeNs);
+    // If the event arrived late, mark the bucket as invalid and skip the event.
+    if (isEventTooLate) {
+        VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+             (long long)mCurrentBucketStartTimeNs);
+        StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
+        invalidateCurrentBucket();
+        mCondition = ConditionState::kUnknown;
         mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
+        return;
     }
+
+    // If the previous condition was unknown, mark the bucket as invalid
+    // because the bucket will contain partial data. For example, the condition
+    // change might happen close to the end of the bucket and we might miss a
+    // lot of data.
+    //
+    // We still want to pull to set the base.
+    if (mCondition == ConditionState::kUnknown) {
+        invalidateCurrentBucket();
+    }
+
+    // Pull and match for the following condition change cases:
+    // unknown/false -> true - condition changed
+    // true -> false - condition changed
+    // true -> true - old condition was true so we can flush the bucket at the
+    // end if needed.
+    //
+    // We don’t need to pull for unknown -> false or false -> false.
+    //
+    // onConditionChangedLocked might happen on bucket boundaries if this is
+    // called before #onDataPulled.
+    if (mIsPulled &&
+        (newCondition == ConditionState::kTrue || mCondition == ConditionState::kTrue)) {
+        pullAndMatchEventsLocked(eventTimeNs, newCondition);
+    }
+
+    // For metrics that use diff, when condition changes from true to false,
+    // clear diff base but don't reset other counts because we may accumulate
+    // more value in the bucket.
+    if (mUseDiff &&
+        (mCondition == ConditionState::kTrue && newCondition == ConditionState::kFalse)) {
+        resetBase();
+    }
+
+    // Update condition state after pulling.
+    mCondition = newCondition;
+
+    flushIfNeededLocked(eventTimeNs);
+    mConditionTimer.onConditionChanged(mCondition, eventTimeNs);
 }
 
 void ValueMetricProducer::pullAndMatchEventsLocked(const int64_t timestampNs,
@@ -472,33 +465,33 @@
 void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
                                        bool pullSuccess, int64_t originalPullTimeNs) {
     std::lock_guard<std::mutex> lock(mMutex);
-        if (mCondition == ConditionState::kTrue) {
-            // If the pull failed, we won't be able to compute a diff.
-            if (!pullSuccess) {
-                invalidateCurrentBucket();
+    if (mCondition == ConditionState::kTrue) {
+        // If the pull failed, we won't be able to compute a diff.
+        if (!pullSuccess) {
+            invalidateCurrentBucket();
+        } else {
+            bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
+            if (isEventLate) {
+                // If the event is late, we are in the middle of a bucket. Just
+                // process the data without trying to snap the data to the nearest bucket.
+                accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
             } else {
-                bool isEventLate = originalPullTimeNs < getCurrentBucketEndTimeNs();
-                if (isEventLate) {
-                    // If the event is late, we are in the middle of a bucket. Just
-                    // process the data without trying to snap the data to the nearest bucket.
-                    accumulateEvents(allData, originalPullTimeNs, originalPullTimeNs, mCondition);
-                } else {
-                    // For scheduled pulled data, the effective event time is snap to the nearest
-                    // bucket end. In the case of waking up from a deep sleep state, we will
-                    // attribute to the previous bucket end. If the sleep was long but not very
-                    // long, we will be in the immediate next bucket. Previous bucket may get a
-                    // larger number as we pull at a later time than real bucket end.
-                    //
-                    // If the sleep was very long, we skip more than one bucket before sleep. In
-                    // this case, if the diff base will be cleared and this new data will serve as
-                    // new diff base.
-                    int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
-                    StatsdStats::getInstance().noteBucketBoundaryDelayNs(
-                            mMetricId, originalPullTimeNs - bucketEndTime);
-                    accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
-                }
+                // For scheduled pulled data, the effective event time is snap to the nearest
+                // bucket end. In the case of waking up from a deep sleep state, we will
+                // attribute to the previous bucket end. If the sleep was long but not very
+                // long, we will be in the immediate next bucket. Previous bucket may get a
+                // larger number as we pull at a later time than real bucket end.
+                //
+                // If the sleep was very long, we skip more than one bucket before sleep. In
+                // this case, if the diff base will be cleared and this new data will serve as
+                // new diff base.
+                int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
+                StatsdStats::getInstance().noteBucketBoundaryDelayNs(
+                        mMetricId, originalPullTimeNs - bucketEndTime);
+                accumulateEvents(allData, originalPullTimeNs, bucketEndTime, mCondition);
             }
         }
+    }
 
     // We can probably flush the bucket. Since we used bucketEndTime when calling
     // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
@@ -579,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());
           }
         }
     }
@@ -821,7 +814,7 @@
 void ValueMetricProducer::flushIfNeededLocked(const int64_t& eventTimeNs) {
     int64_t currentBucketEndTimeNs = getCurrentBucketEndTimeNs();
     if (eventTimeNs < currentBucketEndTimeNs) {
-        VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+        VLOG("eventTime is %lld, less than current bucket end time %lld", (long long)eventTimeNs,
              (long long)(currentBucketEndTimeNs));
         return;
     }
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/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index c9f069d..db0bca0 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -23,8 +23,8 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.sysprop.TelephonyProperties;
 import android.telecom.Log;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -34,7 +34,6 @@
 import com.android.internal.os.BaseCommand;
 import com.android.internal.telecom.ITelecomService;
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.TelephonyProperties;
 
 import java.io.PrintStream;
 
@@ -371,7 +370,7 @@
      * "" (empty string) for a phone in SS mode
      */
     private void runGetSimConfig() throws RemoteException {
-        System.out.println(SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG));
+        System.out.println(TelephonyProperties.multi_sim_config().orElse(""));
     }
 
     private void runGetMaxPhones() throws RemoteException {
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/animation/FloatEvaluator.java b/core/java/android/animation/FloatEvaluator.java
index 9463aa1..ae90e37 100644
--- a/core/java/android/animation/FloatEvaluator.java
+++ b/core/java/android/animation/FloatEvaluator.java
@@ -24,7 +24,7 @@
     /**
      * This function returns the result of linearly interpolating the start and end values, with
      * <code>fraction</code> representing the proportion between the start and end values. The
-     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
      * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
      * and <code>t</code> is <code>fraction</code>.
      *
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ebb03e7..764e599 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -296,6 +296,7 @@
     /**
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static void setDurationScale(float durationScale) {
         sDurationScale = durationScale;
@@ -304,6 +305,7 @@
     /**
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static float getDurationScale() {
         return sDurationScale;
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/Activity.java b/core/java/android/app/Activity.java
index 6182def..f54e841 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2797,6 +2797,7 @@
      * @see View#onMovedToDisplay(int, Configuration)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public void onMovedToDisplay(int displayId, Configuration config) {
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2e9b2af..6d63fd09 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -155,6 +155,12 @@
      */
     public static final int INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL = 1 << 1;
 
+    /**
+     * Disable test API access for the newly started instrumentation.
+     * @hide
+     */
+    public static final int INSTR_FLAG_DISABLE_TEST_API_CHECKS = 1 << 2;
+
     static final class UidObserver extends IUidObserver.Stub {
         final OnUidImportanceListener mListener;
         final Context mContext;
@@ -2976,6 +2982,7 @@
          *
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final int IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
 
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 92aabb5..de7cc9d 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -219,7 +219,7 @@
      * @param userId
      * @param event
      * @param appToken ActivityRecord's appToken.
-     * @param taskRoot TaskRecord's root
+     * @param taskRoot Task's root
      */
     public abstract void updateActivityUsageStats(
             ComponentName activity, @UserIdInt int userId, int event, IBinder appToken,
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 79ab67a..91f8a3c 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -412,8 +412,8 @@
             return;
         }
         mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
-        mTaskEmbedder.setListener(null);
         mTaskEmbedder.release();
+        mTaskEmbedder.setListener(null);
 
         mGuard.close();
         mOpened = false;
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 765c358..afb7871 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -581,6 +581,7 @@
     @UnsupportedAppUsage
     public static final int OP_NONE = -1;
     /** @hide Access to coarse location information. */
+    @UnsupportedAppUsage
     @TestApi
     public static final int OP_COARSE_LOCATION = 0;
     /** @hide Access to fine location information. */
@@ -653,6 +654,7 @@
     @UnsupportedAppUsage
     public static final int OP_WRITE_SETTINGS = 23;
     /** @hide Required to draw on top of other apps. */
+    @UnsupportedAppUsage
     @TestApi
     public static final int OP_SYSTEM_ALERT_WINDOW = 24;
     /** @hide */
@@ -662,6 +664,7 @@
     @UnsupportedAppUsage
     public static final int OP_CAMERA = 26;
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public static final int OP_RECORD_AUDIO = 27;
     /** @hide */
@@ -809,6 +812,7 @@
     @UnsupportedAppUsage
     public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
     /** @hide Any app start foreground service. */
+    @UnsupportedAppUsage
     @TestApi
     public static final int OP_START_FOREGROUND = 76;
     /** @hide */
@@ -2147,6 +2151,7 @@
      * Retrieve the permission associated with an operation, or null if there is not one.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static String opToPermission(int op) {
         return sOpPerms[op];
@@ -2179,6 +2184,7 @@
      * to the corresponding app op.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static int permissionToOpCode(String permission) {
         Integer boxedOpCode = sPermToOp.get(permission);
@@ -5281,6 +5287,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     @RequiresPermission(android.Manifest.permission.MANAGE_APP_OPS_MODES)
     public void setMode(int code, int uid, String packageName, @Mode int mode) {
@@ -5627,6 +5634,7 @@
     /**
      * {@hide}
      */
+    @UnsupportedAppUsage
     @TestApi
     public static int strOpToOp(@NonNull String op) {
         Integer val = sOpStrToOp.get(op);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 466c1a9..1c8f494 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -128,6 +128,13 @@
     }
 
     @Override
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver, IntentFilter filter,
+            String broadcastPermission, Handler scheduler) {
+        return registerReceiverAsUser(
+                receiver, UserHandle.ALL, filter, broadcastPermission, scheduler);
+    }
+
+    @Override
     public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, String broadcastPermission, Handler scheduler) {
         if (receiver == null) {
@@ -1531,6 +1538,13 @@
     }
 
     @Override
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        return registerReceiverAsUser(receiver, UserHandle.ALL,
+                filter, broadcastPermission, scheduler);
+    }
+
+    @Override
     public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, String broadcastPermission, Handler scheduler) {
         return registerReceiverInternal(receiver, user.getIdentifier(),
@@ -2347,6 +2361,7 @@
         return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
     }
 
+    @UnsupportedAppUsage
     @TestApi
     @Override
     public Display getDisplay() {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 088c245..39f1e95 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -219,7 +219,6 @@
             @Nullable Message cancelCallback) {
         this(context);
         mCancelable = cancelable;
-        updateWindowForCancelable();
         mCancelMessage = cancelCallback;
     }
 
@@ -227,7 +226,6 @@
             @Nullable OnCancelListener cancelListener) {
         this(context);
         mCancelable = cancelable;
-        updateWindowForCancelable();
         setOnCancelListener(cancelListener);
     }
 
@@ -1249,7 +1247,6 @@
      */
     public void setCancelable(boolean flag) {
         mCancelable = flag;
-        updateWindowForCancelable();
     }
 
     /**
@@ -1263,7 +1260,6 @@
     public void setCanceledOnTouchOutside(boolean cancel) {
         if (cancel && !mCancelable) {
             mCancelable = true;
-            updateWindowForCancelable();
         }
         
         mWindow.setCloseOnTouchOutside(cancel);
@@ -1415,8 +1411,4 @@
             }
         }
     }
-
-    private void updateWindowForCancelable() {
-        mWindow.setCloseOnSwipeEnabled(mCancelable);
-    }
 }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index f0b3546..e858e6a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1215,7 +1215,8 @@
         }
 
         // Rewrite the R 'constants' for all library apks.
-        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers();
+        SparseArray<String> packageIdentifiers = getAssets().getAssignedPackageIdentifiers(
+                false, false);
         final int N = packageIdentifiers.size();
         for (int i = 0; i < N; i++) {
             final int id = packageIdentifiers.keyAt(i);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 47118a8..fce7449 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2576,10 +2576,12 @@
             PendingIntent.setOnMarshaledListener(
                     (PendingIntent intent, Parcel out, int outFlags) -> {
                 if (parcel == out) {
-                    if (allPendingIntents == null) {
-                        allPendingIntents = new ArraySet<>();
+                    synchronized (this) {
+                        if (allPendingIntents == null) {
+                            allPendingIntents = new ArraySet<>();
+                        }
+                        allPendingIntents.add(intent);
                     }
-                    allPendingIntents.add(intent);
                 }
             });
         }
@@ -2587,8 +2589,10 @@
             // IMPORTANT: Add marshaling code in writeToParcelImpl as we
             // want to intercept all pending events written to the parcel.
             writeToParcelImpl(parcel, flags);
-            // Must be written last!
-            parcel.writeArraySet(allPendingIntents);
+            synchronized (this) {
+                // Must be written last!
+                parcel.writeArraySet(allPendingIntents);
+            }
         } finally {
             if (collectPendingIntents) {
                 PendingIntent.setOnMarshaledListener(null);
@@ -3200,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/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 6dca5d9..03ee1e9 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1772,7 +1772,7 @@
         @Override
         public int hashCode() {
             return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders,
-                    suppressedVisualEffects);
+                    suppressedVisualEffects, state);
         }
 
         @Override
@@ -1784,10 +1784,10 @@
                     && other.priorityCallSenders == priorityCallSenders
                     && other.priorityMessageSenders == priorityMessageSenders
                     && suppressedVisualEffectsEqual(suppressedVisualEffects,
-                    other.suppressedVisualEffects);
+                    other.suppressedVisualEffects)
+                    && other.state == this.state;
         }
 
-
         private boolean suppressedVisualEffectsEqual(int suppressedEffects,
                 int otherSuppressedVisualEffects) {
             if (suppressedEffects == otherSuppressedVisualEffects) {
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index e6682d6..92bfee2 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -24,12 +24,22 @@
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.IBinder;
+import android.os.IPullAtomCallback;
+import android.os.IPullAtomResultReceiver;
+import android.os.IStatsCompanionService;
 import android.os.IStatsManager;
 import android.os.IStatsPullerCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.AndroidException;
 import android.util.Slog;
+import android.util.StatsEvent;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
 
 /**
  * API for statsd clients to send configurations and retrieve data.
@@ -43,8 +53,12 @@
 
     private final Context mContext;
 
+    @GuardedBy("this")
     private IStatsManager mService;
 
+    @GuardedBy("this")
+    private IStatsCompanionService mStatsCompanion;
+
     /**
      * Long extra of uid that added the relevant stats config.
      */
@@ -449,7 +463,9 @@
      * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
      *
      * @hide
+     * @deprecated Please use registerPullAtomCallback
      */
+    @Deprecated
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public void setPullerCallback(int atomTag, IStatsPullerCallback callback)
             throws StatsUnavailableException {
@@ -472,6 +488,75 @@
         }
     }
 
+
+    /**
+     * Registers a callback for an atom when that atom is to be pulled. The stats service will
+     * invoke pullData in the callback when the stats service determines that this atom needs to be
+     * pulled.
+     *
+     * @param atomTag           The tag of the atom for this puller callback.
+     * @param coolDownNs        The minimum time between successive pulls. A cache of the previous
+     *                          pull will be used if the time between pulls is less than coolDownNs.
+     * @param timeoutNs         The maximum time a pull should take. Statsd will wait timeoutNs for
+     *                          the pull to complete before timing out and marking the pull as
+     *                          failed.
+     * @param additiveFields    Fields that are added when mapping isolated uids to host uids.
+     * @param callback          The callback to be invoked when the stats service pulls the atom.
+     * @throws RemoteException  if unsuccessful due to failing to connect to system server.
+     *
+     * @hide
+     */
+    public void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+            int[] additiveFields, @NonNull StatsPullAtomCallback callback,
+            @NonNull Executor executor) throws RemoteException, SecurityException {
+        synchronized (this) {
+            IStatsCompanionService service = getIStatsCompanionServiceLocked();
+            PullAtomCallbackInternal rec =
+                    new PullAtomCallbackInternal(atomTag, callback, executor);
+            service.registerPullAtomCallback(atomTag, coolDownNs, timeoutNs, additiveFields, rec);
+        }
+    }
+
+    private static class  PullAtomCallbackInternal extends IPullAtomCallback.Stub {
+        public final int mAtomId;
+        public final StatsPullAtomCallback mCallback;
+        public final Executor mExecutor;
+
+        PullAtomCallbackInternal(int atomId, StatsPullAtomCallback callback, Executor executor) {
+            mAtomId = atomId;
+            mCallback = callback;
+            mExecutor = executor;
+        }
+
+        @Override
+        public void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver) {
+            mExecutor.execute(() -> {
+                List<StatsEvent> data = new ArrayList<>();
+                boolean success = mCallback.onPullAtom(atomTag, data);
+                StatsEvent[] arr = new StatsEvent[data.size()];
+                arr = data.toArray(arr);
+                try {
+                    resultReceiver.pullFinished(atomTag, success, arr);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "StatsPullResultReceiver failed for tag " + mAtomId);
+                }
+            });
+        }
+    }
+
+    /**
+     * Callback interface for pulling atoms requested by the stats service.
+     *
+     * @hide
+     */
+    public interface StatsPullAtomCallback {
+        /**
+         * Pull data for the specified atom tag, filling in the provided list of StatsEvent data.
+         * @return if the pull was successful
+         */
+        boolean onPullAtom(int atomTag, List<StatsEvent> data);
+    }
+
     private class StatsdDeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
@@ -481,6 +566,7 @@
         }
     }
 
+    @GuardedBy("this")
     private IStatsManager getIStatsManagerLocked() throws StatsUnavailableException {
         if (mService != null) {
             return mService;
@@ -497,6 +583,16 @@
         return mService;
     }
 
+    @GuardedBy("this")
+    private IStatsCompanionService getIStatsCompanionServiceLocked() {
+        if (mStatsCompanion != null) {
+            return mStatsCompanion;
+        }
+        mStatsCompanion = IStatsCompanionService.Stub.asInterface(
+                ServiceManager.getService("statscompanion"));
+        return mStatsCompanion;
+    }
+
     /**
      * Exception thrown when communication with the stats service fails (eg if it is not available).
      * This might be thrown early during boot before the stats service has started or if it crashed.
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index f4c6b50..8cb094f 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -35,6 +35,8 @@
 import android.util.proto.WireTypeMismatchException;
 import android.view.DisplayInfo;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.io.IOException;
 
 /**
@@ -199,6 +201,7 @@
     /** @hide */
     public static final int PINNED_WINDOWING_MODE_ELEVATION_IN_DIP = 5;
 
+    @UnsupportedAppUsage
     public WindowConfiguration() {
         unset();
     }
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/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
index 8e40449..6bade90 100644
--- a/core/java/android/app/usage/NetworkStatsManager.java
+++ b/core/java/android/app/usage/NetworkStatsManager.java
@@ -146,6 +146,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public void setPollForce(boolean pollForce) {
         if (pollForce) {
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 8691ed4..f73a376 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -16,6 +16,8 @@
 
 package android.content;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -25,6 +27,7 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
@@ -623,6 +626,20 @@
         return mPendingResult;
     }
 
+    /**
+     * Returns the user that the broadcast was sent to.
+     *
+     * <p>It can be used in a receiver registered by
+     * {@link Context#registerReceiverForAllUsers Context.registerReceiverForAllUsers()}
+     * to determine on which user the broadcast was sent.
+     *
+     * @hide
+     */
+    @SystemApi
+    public final @NonNull UserHandle getSendingUser() {
+        return UserHandle.of(getSendingUserId());
+    }
+
     /** @hide */
     public int getSendingUserId() {
         return mPendingResult.mSendingUser;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 2657cc5..61c8db5d 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -65,6 +65,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Size;
+import android.util.SparseArray;
 
 import com.android.internal.util.MimeIconUtils;
 import com.android.internal.util.Preconditions;
@@ -2381,15 +2382,15 @@
      *            true.
      * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
+     * @deprecated callers should consider migrating to
+     *             {@link #notifyChange(Uri, ContentObserver, int)}, as it
+     *             offers support for many more options than just
+     *             {@link #NOTIFY_SYNC_TO_NETWORK}.
      */
+    @Deprecated
     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
             boolean syncToNetwork) {
-        Preconditions.checkNotNull(uri, "uri");
-        notifyChange(
-                ContentProvider.getUriWithoutUserId(uri),
-                observer,
-                syncToNetwork,
-                ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
+        notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0);
     }
 
     /**
@@ -2398,10 +2399,10 @@
      * To observe events sent through this call, use
      * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
      * <p>
-     * If syncToNetwork is true, this will attempt to schedule a local sync
-     * using the sync adapter that's registered for the authority of the
-     * provided uri. No account will be passed to the sync adapter, so all
-     * matching accounts will be synchronized.
+     * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
+     * a local sync using the sync adapter that's registered for the authority
+     * of the provided uri. No account will be passed to the sync adapter, so
+     * all matching accounts will be synchronized.
      * <p>
      * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
      * notifications must be backed by a valid {@link ContentProvider}.
@@ -2427,21 +2428,71 @@
     }
 
     /**
+     * Notify registered observers that several rows have been updated.
+     * <p>
+     * To observe events sent through this call, use
+     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
+     * <p>
+     * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule
+     * a local sync using the sync adapter that's registered for the authority
+     * of the provided uri. No account will be passed to the sync adapter, so
+     * all matching accounts will be synchronized.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
+     * notifications must be backed by a valid {@link ContentProvider}.
+     *
+     * @param uris The uris of the content that was changed.
+     * @param observer The observer that originated the change, may be
+     *            <code>null</null>. The observer that originated the change
+     *            will only receive the notification if it has requested to
+     *            receive self-change notifications by implementing
+     *            {@link ContentObserver#deliverSelfNotifications()} to return
+     *            true.
+     * @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
+     *            {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
+     */
+    public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+        Preconditions.checkNotNull(uris, "uris");
+
+        // Cluster based on user ID
+        final SparseArray<ArrayList<Uri>> clusteredByUser = new SparseArray<>();
+        for (Uri uri : uris) {
+            final int userId = ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
+            ArrayList<Uri> list = clusteredByUser.get(userId);
+            if (list == null) {
+                list = new ArrayList<>();
+                clusteredByUser.put(userId, list);
+            }
+            list.add(ContentProvider.getUriWithoutUserId(uri));
+        }
+
+        for (int i = 0; i < clusteredByUser.size(); i++) {
+            final int userId = clusteredByUser.keyAt(i);
+            final ArrayList<Uri> list = clusteredByUser.valueAt(i);
+            notifyChange(list.toArray(new Uri[list.size()]), observer, flags, userId);
+        }
+    }
+
+    /**
      * Notify registered observers within the designated user(s) that a row was updated.
      *
+     * @deprecated callers should consider migrating to
+     *             {@link #notifyChange(Uri, ContentObserver, int)}, as it
+     *             offers support for many more options than just
+     *             {@link #NOTIFY_SYNC_TO_NETWORK}.
      * @hide
      */
+    @Deprecated
     public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
             @UserIdInt int userHandle) {
-        try {
-            getContentService().notifyChange(
-                    uri, observer == null ? null : observer.getContentObserver(),
-                    observer != null && observer.deliverSelfNotifications(),
-                    syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
-                    userHandle, mTargetSdkVersion, mContext.getPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle);
+    }
+
+    /** {@hide} */
+    public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
+            @UserIdInt int userHandle) {
+        notifyChange(new Uri[] { uri }, observer, flags, userHandle);
     }
 
     /**
@@ -2449,11 +2500,11 @@
      *
      * @hide
      */
-    public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
+    public void notifyChange(@NonNull Uri[] uris, ContentObserver observer, @NotifyFlags int flags,
             @UserIdInt int userHandle) {
         try {
             getContentService().notifyChange(
-                    uri, observer == null ? null : observer.getContentObserver(),
+                    uris, observer == null ? null : observer.getContentObserver(),
                     observer != null && observer.deliverSelfNotifications(), flags,
                     userHandle, mTargetSdkVersion, mContext.getPackageName());
         } catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6e58383..03b4913 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2072,7 +2072,7 @@
      *               Intent will receive the broadcast.
      * @param receiverPermissions Array of names of permissions that a receiver must hold
      *                            in order to receive your broadcast.
-     *                            If null or empty, no permissions are required.
+     *                            If empty, no permissions are required.
      *
      * @see android.content.BroadcastReceiver
      * @see #registerReceiver
@@ -2081,8 +2081,11 @@
      * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
      * @hide
      */
-    public abstract void sendBroadcastMultiplePermissions(Intent intent,
-            String[] receiverPermissions);
+    @SystemApi
+    public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+            @NonNull String[] receiverPermissions) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
 
     /**
      * Broadcast the given intent to all interested BroadcastReceivers, allowing
@@ -2818,6 +2821,37 @@
             @Nullable Handler scheduler, @RegisterReceiverFlags int flags);
 
     /**
+     * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)}
+     * but this receiver will receive broadcasts that are sent to all users. The receiver can
+     * use {@link BroadcastReceiver#getSendingUser} to determine on which user the broadcast
+     * was sent.
+     *
+     * @param receiver The BroadcastReceiver to handle the broadcast.
+     * @param filter Selects the Intent broadcasts to be received.
+     * @param broadcastPermission String naming a permissions that a
+     *      broadcaster must hold in order to send an Intent to you. If {@code null},
+     *      no permission is required.
+     * @param scheduler Handler identifying the thread that will receive
+     *      the Intent. If {@code null}, the main thread of the process will be used.
+     *
+     * @return The first sticky intent found that matches <var>filter</var>,
+     *         or {@code null} if there are none.
+     *
+     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
+     * @see #sendBroadcast
+     * @see #unregisterReceiver
+     * @hide
+     */
+    @Nullable
+    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+    @SystemApi
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * @hide
      * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
      * but for a specific user.  This receiver will receiver broadcasts that
@@ -5376,6 +5410,7 @@
      * Get the user associated with this context
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public @UserIdInt int getUserId() {
         return android.os.UserHandle.myUserId();
@@ -5506,6 +5541,7 @@
      * @return Returns the {@link Display} object this context is associated with.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public abstract Display getDisplay();
 
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 714e9fb..b04f781 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -464,7 +464,8 @@
 
     /** @hide */
     @Override
-    public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
+    public void sendBroadcastMultiplePermissions(@NonNull Intent intent,
+            @NonNull String[] receiverPermissions) {
         mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions);
     }
 
@@ -670,6 +671,17 @@
 
     /** @hide */
     @Override
+    @Nullable
+    @SystemApi
+    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
+            @NonNull IntentFilter filter, @Nullable String broadcastPermission,
+            @Nullable Handler scheduler) {
+        return mBase.registerReceiverForAllUsers(receiver, filter, broadcastPermission,
+                scheduler);
+    }
+
+    /** @hide */
+    @Override
     @UnsupportedAppUsage
     public Intent registerReceiverAsUser(
         BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
@@ -962,6 +974,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     @Override
     public Display getDisplay() {
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index a34a995..03c99e1 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -51,7 +51,7 @@
      *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL
      *     USER_CURRENT are properly interpreted.
      */
-    void notifyChange(in Uri uri, IContentObserver observer,
+    void notifyChange(in Uri[] uris, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags,
             int userHandle, int targetSdkVersion, String callingPackage);
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4e7e713..ca374f93 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1940,6 +1940,7 @@
     @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS)
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     @SystemApi
+    @TestApi
     public static final String ACTION_MANAGE_DEFAULT_APP =
             "android.intent.action.MANAGE_DEFAULT_APP";
 
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index 3f64515..0eea47a 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -20,6 +20,9 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.ArrayUtils;
 
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -139,10 +142,10 @@
     public final long[] perSourceLastSuccessTimes = new long[SOURCE_COUNT];
     public final long[] perSourceLastFailureTimes = new long[SOURCE_COUNT];
 
-  // Warning: It is up to the external caller to ensure there are
-  // no race conditions when accessing this list
-  @UnsupportedAppUsage
-  private ArrayList<Long> periodicSyncTimes;
+    // Warning: It is up to the external caller to ensure there are
+    // no race conditions when accessing this list
+    @UnsupportedAppUsage
+    private ArrayList<Long> periodicSyncTimes;
 
     private final ArrayList<Long> mLastEventTimes = new ArrayList<>();
     private final ArrayList<String> mLastEvents = new ArrayList<>();
@@ -292,9 +295,28 @@
         }
     }
 
+    /**
+     * Copies all data from the given SyncStatusInfo object.
+     *
+     * @param other the SyncStatusInfo object to copy data from
+     */
     public SyncStatusInfo(SyncStatusInfo other) {
         authorityId = other.authorityId;
+        copyFrom(other);
+    }
 
+    /**
+     * Copies all data from the given SyncStatusInfo object except for its authority id.
+     *
+     * @param authorityId the new authority id
+     * @param other the SyncStatusInfo object to copy data from
+     */
+    public SyncStatusInfo(int authorityId, SyncStatusInfo other) {
+        this.authorityId = authorityId;
+        copyFrom(other);
+    }
+
+    private void copyFrom(SyncStatusInfo other) {
         other.totalStats.copyTo(totalStats);
         other.todayStats.copyTo(todayStats);
         other.yesterdayStats.copyTo(yesterdayStats);
@@ -323,6 +345,14 @@
         System.arraycopy(from, 0, to, 0, to.length);
     }
 
+    public int getPeriodicSyncTimesSize() {
+        return periodicSyncTimes == null ? 0 : periodicSyncTimes.size();
+    }
+
+    public void addPeriodicSyncTime(long time) {
+        periodicSyncTimes = ArrayUtils.add(periodicSyncTimes, time);
+    }
+
     @UnsupportedAppUsage
     public void setPeriodicSyncTime(int index, long when) {
         // The list is initialized lazily when scheduling occurs so we need to make sure
@@ -347,6 +377,24 @@
         }
     }
 
+    /**
+     * Populates {@code mLastEventTimes} and {@code mLastEvents} with the given list. <br>
+     * <i>Note: This method is mainly used to repopulate the event info from disk and it will clear
+     * both {@code mLastEventTimes} and {@code mLastEvents} before populating.</i>
+     *
+     * @param lastEventInformation the list to populate with
+     */
+    public void populateLastEventsInformation(ArrayList<Pair<Long, String>> lastEventInformation) {
+        mLastEventTimes.clear();
+        mLastEvents.clear();
+        final int size = lastEventInformation.size();
+        for (int i = 0; i < size; i++) {
+            final Pair<Long, String> lastEventInfo = lastEventInformation.get(i);
+            mLastEventTimes.add(lastEventInfo.first);
+            mLastEvents.add(lastEventInfo.second);
+        }
+    }
+
     /** */
     public void addEvent(String message) {
         if (mLastEventTimes.size() >= MAX_EVENT_COUNT) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 415c242..e724443 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1237,20 +1237,17 @@
      * Determines whether the {@link Activity} is considered translucent or floating.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static boolean isTranslucentOrFloating(TypedArray attributes) {
         final boolean isTranslucent =
                 attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
                         false);
-        final boolean isSwipeToDismiss = !attributes.hasValue(
-                com.android.internal.R.styleable.Window_windowIsTranslucent)
-                && attributes.getBoolean(
-                        com.android.internal.R.styleable.Window_windowSwipeToDismiss, false);
         final boolean isFloating =
                 attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsFloating,
                         false);
 
-        return isFloating || isTranslucent || isSwipeToDismiss;
+        return isFloating || isTranslucent;
     }
 
     /**
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index d0a61eb..37c6f57 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -470,6 +470,7 @@
      *
      * {@hide}
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
 
@@ -733,6 +734,7 @@
      * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public @ApplicationInfoPrivateFlags int privateFlags;
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index e0d6260..c56c307 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3332,6 +3332,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final String SYSTEM_SHARED_LIBRARY_SERVICES = "android.ext.services";
 
@@ -3344,6 +3345,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
 
@@ -3977,6 +3979,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @NonNull
     @TestApi
     public abstract String getPermissionControllerPackageName();
@@ -4684,6 +4687,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
 
@@ -4694,6 +4698,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
 
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 23e7720..070e282 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1491,9 +1491,17 @@
      */
     @UnsupportedAppUsage
     public SparseArray<String> getAssignedPackageIdentifiers() {
+        return getAssignedPackageIdentifiers(true, true);
+    }
+
+    /**
+     * @hide
+     */
+    public SparseArray<String> getAssignedPackageIdentifiers(boolean includeOverlays,
+            boolean includeLoaders) {
         synchronized (this) {
             ensureValidLocked();
-            return nativeGetAssignedPackageIdentifiers(mObject);
+            return nativeGetAssignedPackageIdentifiers(mObject, includeOverlays, includeLoaders);
         }
     }
 
@@ -1557,7 +1565,7 @@
             int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
             int uiMode, int colorMode, int majorVersion);
     private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
-            long ptr);
+            long ptr, boolean includeOverlays, boolean includeLoaders);
 
     // File native methods.
     private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 053444b..5a45d9f 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -613,6 +613,16 @@
      */
     public int navigationHidden;
 
+    /** @hide **/
+    @IntDef(prefix = {"ORIENTATION_"}, value = {
+            ORIENTATION_UNDEFINED,
+            ORIENTATION_PORTRAIT,
+            ORIENTATION_LANDSCAPE,
+            ORIENTATION_SQUARE
+    })
+    public @interface Orientation {
+    }
+
     /** Constant for {@link #orientation}: a value indicating that no value has been set. */
     public static final int ORIENTATION_UNDEFINED = 0;
     /** Constant for {@link #orientation}, value corresponding to the
@@ -630,6 +640,7 @@
      * Overall orientation of the screen.  May be one of
      * {@link #ORIENTATION_LANDSCAPE}, {@link #ORIENTATION_PORTRAIT}.
      */
+    @Orientation
     public int orientation;
 
     /** Constant for {@link #uiMode}: bits that encode the mode type. */
@@ -798,6 +809,7 @@
      * {@link ActivityInfo#CONFIG_ASSETS_PATHS}.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public int assetsSeq;
 
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index a231a92..3d0ac61 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -23,6 +23,8 @@
 import android.util.Log;
 import android.util.Printer;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.util.ArrayList;
 
 /**
@@ -116,9 +118,15 @@
      * @see #nativeGetPagerStats(PagerStats)
      */
     public static class PagerStats {
+
+        @UnsupportedAppUsage
+        public PagerStats() {
+        }
+
         /** the current amount of memory checked out by sqlite using sqlite3_malloc().
          * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
          */
+        @UnsupportedAppUsage
         public int memoryUsed;
 
         /** the number of bytes of page cache allocation which could not be sattisfied by the
@@ -128,16 +136,19 @@
          * that overflowed because no space was left in the page cache.
          * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
          */
+        @UnsupportedAppUsage
         public int pageCacheOverflow;
 
         /** records the largest memory allocation request handed to sqlite3.
          * documented at http://www.sqlite.org/c3ref/c_status_malloc_size.html
          */
+        @UnsupportedAppUsage
         public int largestMemAlloc;
 
         /** a list of {@link DbStats} - one for each main database opened by the applications
          * running on the android device
          */
+        @UnsupportedAppUsage
         public ArrayList<DbStats> dbStats;
     }
 
@@ -146,16 +157,20 @@
      */
     public static class DbStats {
         /** name of the database */
+        @UnsupportedAppUsage
         public String dbName;
 
         /** the page size for the database */
+        @UnsupportedAppUsage
         public long pageSize;
 
         /** the database size */
+        @UnsupportedAppUsage
         public long dbSize;
 
         /**
          * Number of lookaside slots: http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
+        @UnsupportedAppUsage
         public int lookaside;
 
         /** statement cache stats: hits/misses/cachesize */
@@ -175,6 +190,7 @@
      * return all pager and database stats for the current process.
      * @return {@link PagerStats}
      */
+    @UnsupportedAppUsage
     public static PagerStats getDatabaseInfo() {
         PagerStats stats = new PagerStats();
         nativeGetPagerStats(stats);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index fc90096..b61b1ef 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -404,7 +404,7 @@
                             "Camera service is currently unavailable");
                     }
                     cameraUser = cameraService.connectDevice(callbacks, cameraId,
-                            mContext.getOpPackageName(), uid);
+                            mContext.getOpPackageName(), mContext.getFeatureId(), uid);
                 } else {
                     // Use legacy camera implementation for HAL1 devices
                     int id;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index e3259ff..88877e2 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -478,6 +478,7 @@
      * @return an array of capability values for this instance.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public @NetCapability int[] getCapabilities() {
         return BitUtils.unpackBits(mNetworkCapabilities);
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..ec39199 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -932,9 +932,14 @@
         }
 
         int result = -1;
-        try {
-            result = handleShellCommand(new ParcelFileDescriptor(in),
-                    new ParcelFileDescriptor(out), new ParcelFileDescriptor(err), args);
+        try (ParcelFileDescriptor inPfd = ParcelFileDescriptor.dup(in);
+                ParcelFileDescriptor outPfd = ParcelFileDescriptor.dup(out);
+                ParcelFileDescriptor errPfd = ParcelFileDescriptor.dup(err)) {
+            result = handleShellCommand(inPfd, outPfd, errPfd, args);
+        } catch (IOException e) {
+            PrintWriter pw = new FastPrintWriter(new FileOutputStream(err));
+            pw.println("dup() failed: " + e.getMessage());
+            pw.flush();
         } finally {
             resultReceiver.send(result, null);
         }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 6a709b5..400d981 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -26,17 +26,17 @@
 import android.app.ActivityThread;
 import android.app.Application;
 import android.content.Context;
+import android.sysprop.TelephonyProperties;
 import android.text.TextUtils;
 import android.util.Slog;
 import android.view.View;
 
-import com.android.internal.telephony.TelephonyProperties;
-
 import dalvik.system.VMRuntime;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * Information about the current build, extracted from system properties.
@@ -99,7 +99,8 @@
      * {@link #getRadioVersion} instead.
      */
     @Deprecated
-    public static final String RADIO = getString(TelephonyProperties.PROPERTY_BASEBAND_VERSION);
+    public static final String RADIO = joinListOrElse(
+            TelephonyProperties.baseband_version(), UNKNOWN);
 
     /** The name of the hardware (from the kernel command line or /proc). */
     public static final String HARDWARE = getString("ro.hardware");
@@ -108,6 +109,7 @@
      * Whether this build was for an emulator device.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
 
@@ -336,8 +338,8 @@
         /**
          * @hide
          */
-        @TestApi
         @UnsupportedAppUsage
+        @TestApi
         public static final String[] ACTIVE_CODENAMES = "REL".equals(ALL_CODENAMES[0])
                 ? new String[0] : ALL_CODENAMES;
 
@@ -1088,7 +1090,8 @@
         final String requiredBootloader = SystemProperties.get("ro.build.expect.bootloader");
         final String currentBootloader = SystemProperties.get("ro.bootloader");
         final String requiredRadio = SystemProperties.get("ro.build.expect.baseband");
-        final String currentRadio = SystemProperties.get("gsm.version.baseband");
+        final String currentRadio = joinListOrElse(
+                TelephonyProperties.baseband_version(), "");
 
         if (TextUtils.isEmpty(system)) {
             Slog.e(TAG, "Required ro.build.fingerprint is empty!");
@@ -1262,8 +1265,7 @@
      * null (if, for instance, the radio is not currently on).
      */
     public static String getRadioVersion() {
-        String propVal = SystemProperties.get(TelephonyProperties.PROPERTY_BASEBAND_VERSION);
-        return TextUtils.isEmpty(propVal) ? null : propVal;
+        return joinListOrElse(TelephonyProperties.baseband_version(), null);
     }
 
     @UnsupportedAppUsage
@@ -1288,4 +1290,10 @@
             return -1;
         }
     }
+
+    private static <T> String joinListOrElse(List<T> list, String defaultValue) {
+        String ret = list.stream().map(elem -> elem == null ? "" : elem.toString())
+                .collect(Collectors.joining(","));
+        return ret.isEmpty() ? defaultValue : ret;
+    }
 }
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 947b0a1..034e6a7 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -177,13 +177,6 @@
     }
 
     /**
-     * Check whether application is debuggable
-     */
-    private static boolean isDebuggable(Context context) {
-        return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
-    }
-
-    /**
      * Check whether application is has set the manifest metadata for layer injection.
      */
     private static boolean canInjectLayers(ApplicationInfo ai) {
@@ -246,7 +239,7 @@
         // 2. ENABLE_GPU_DEBUG_LAYERS is true
         // 3. Package name is equal to GPU_DEBUG_APP
 
-        if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1) || canInjectLayers(ai)) {
+        if (isDebuggable() || canInjectLayers(ai)) {
 
             final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
 
@@ -441,9 +434,7 @@
      * Check for ANGLE debug package, but only for apps that can load them (dumpable)
      */
     private String getAngleDebugPackage(Context context, Bundle coreSettings) {
-        final boolean appIsDebuggable = isDebuggable(context);
-        final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
-        if (appIsDebuggable || deviceIsDebuggable) {
+        if (isDebuggable()) {
             String debugPackage;
 
             if (coreSettings != null) {
@@ -478,12 +469,8 @@
          *  - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
          *    debugging (PR_SET_DUMPABLE).
          */
-        final boolean appIsDebuggable = isDebuggable(context);
-        final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
-        if (!(appIsDebuggable || deviceIsDebuggable)) {
-            Log.v(TAG, "Skipping loading temporary rules file: "
-                    + "appIsDebuggable = " + appIsDebuggable + ", "
-                    + "adbRootEnabled = " + deviceIsDebuggable);
+        if (!isDebuggable()) {
+            Log.v(TAG, "Skipping loading temporary rules file");
             return false;
         }
 
@@ -742,7 +729,7 @@
 
         final boolean enablePrereleaseDriver =
                 (ai.metaData != null && ai.metaData.getBoolean(METADATA_DEVELOPER_DRIVER_ENABLE))
-                || getCanLoadSystemLibraries() == 1;
+                || isDebuggable();
 
         // Priority for Game Driver settings global on confliction (Higher priority comes first):
         // 1. GAME_DRIVER_ALL_APPS
@@ -918,7 +905,7 @@
         return "";
     }
 
-    private static native int getCanLoadSystemLibraries();
+    private static native boolean isDebuggable();
     private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
     private static native void setDebugLayers(String layers);
     private static native void setDebugLayersGLES(String layers);
diff --git a/core/java/android/os/IPullAtomCallback.aidl b/core/java/android/os/IPullAtomCallback.aidl
new file mode 100644
index 0000000..88d3c3e
--- /dev/null
+++ b/core/java/android/os/IPullAtomCallback.aidl
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.os.IPullAtomResultReceiver;
+
+/**
+  * Binder interface to pull atoms for the stats service.
+  * {@hide}
+  */
+interface IPullAtomCallback {
+    /**
+     * Initiate a request for a pull for an atom.
+     */
+     void onPullAtom(int atomTag, IPullAtomResultReceiver resultReceiver);
+
+}
diff --git a/core/java/android/os/IPullAtomResultReceiver.aidl b/core/java/android/os/IPullAtomResultReceiver.aidl
new file mode 100644
index 0000000..bfb35ff
--- /dev/null
+++ b/core/java/android/os/IPullAtomResultReceiver.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.util.StatsEvent;
+
+/**
+  * Binder interface to pull atoms for the stats service.
+  * {@hide}
+  */
+interface IPullAtomResultReceiver {
+
+    /**
+     * Indicate that a pull request for an atom is complete.
+     */
+     oneway void pullFinished(int atomTag, boolean success, in StatsEvent[] output);
+
+}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 0751b96..22a2537 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.os.IPullAtomCallback;
 import android.os.StatsDimensionsValue;
 import android.os.StatsLogEventWrapper;
 
@@ -85,4 +86,8 @@
 
     /** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
     oneway void triggerUidSnapshot();
+
+    /** Tells StatsCompanionService to tell statsd to register a puller for the given atom id */
+    oneway void registerPullAtomCallback(int atomTag, long coolDownNs, long timeoutNs,
+            in int[] additiveFields, IPullAtomCallback pullerCallback);
 }
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index e3f9326..29871b6 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -17,6 +17,7 @@
 package android.os;
 
 import android.os.IStatsPullerCallback;
+import android.os.IPullAtomCallback;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -188,11 +189,19 @@
      * for the specified vendor atom tag.
      *
      * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
+     * @deprecated please use registerPullAtomCallback.
      */
     oneway void registerPullerCallback(int atomTag, IStatsPullerCallback pullerCallback,
                                        String packageName);
 
    /**
+    * Registers a puller callback function that, when invoked, pulls the data
+    * for the specified atom tag.
+    */
+    oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownNs, long timeoutNs,
+                           in int[] additiveFields, IPullAtomCallback pullerCallback);
+
+   /**
     * Unregisters a puller callback function for the given vendor atom.
     *
     * Requires Manifest.permission.DUMP and Manifest.permission.PACKAGE_USAGE_STATS
diff --git a/core/java/android/os/IStatsPullerCallback.aidl b/core/java/android/os/IStatsPullerCallback.aidl
index 1684aeb..c3e1e55 100644
--- a/core/java/android/os/IStatsPullerCallback.aidl
+++ b/core/java/android/os/IStatsPullerCallback.aidl
@@ -19,6 +19,7 @@
 import android.os.StatsLogEventWrapper;
 
 /**
+  * DEPRECATED
   * Binder interface to pull atoms for the stats service.
   * {@hide}
   */
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index c5f1698..f98fdc3 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -468,6 +468,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public int postSyncBarrier() {
         return postSyncBarrier(SystemClock.uptimeMillis());
@@ -512,6 +513,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public void removeSyncBarrier(int token) {
         // Remove a sync barrier token from the queue.
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 43b9c67..6408f61 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -229,6 +229,7 @@
      * First uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int FIRST_ISOLATED_UID = 99000;
 
@@ -236,6 +237,7 @@
      * Last uid used for fully isolated sandboxed processes (with no permissions of their own)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int LAST_ISOLATED_UID = 99999;
 
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 48fc2a6..e3f6e12 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -888,7 +888,7 @@
         }
         List<SubscriptionInfo> invisibleSubs = new ArrayList<>();
         for (SubscriptionInfo sub : availableSubs) {
-            if (sub.isEmbedded() && !subscriptionManager.isSubscriptionVisible(sub)) {
+            if (sub.isEmbedded() && sub.getGroupUuid() != null && sub.isOpportunistic()) {
                 invisibleSubs.add(sub);
             }
         }
diff --git a/core/java/android/os/RemoteException.java b/core/java/android/os/RemoteException.java
index 2e673a8..10ef279 100644
--- a/core/java/android/os/RemoteException.java
+++ b/core/java/android/os/RemoteException.java
@@ -16,7 +16,7 @@
 
 package android.os;
 
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.NonNull;
 import android.util.AndroidException;
 
 /**
@@ -37,7 +37,15 @@
         super(message, cause, enableSuppression, writableStackTrace);
     }
 
-    /** {@hide} */
+    /**
+     * Rethrow this as an unchecked runtime exception.
+     * <p>
+     * Apps making calls into other processes may end up persisting internal
+     * state or making security decisions based on the perceived success or
+     * failure of a call, or any default values returned. For this reason, we
+     * want to strongly throw when there was trouble with the transaction.
+     */
+    @NonNull
     public RuntimeException rethrowAsRuntimeException() {
         throw new RuntimeException(this);
     }
@@ -52,10 +60,8 @@
      * state or making security decisions based on the perceived success or
      * failure of a call, or any default values returned. For this reason, we
      * want to strongly throw when there was trouble with the transaction.
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
+    @NonNull
     public RuntimeException rethrowFromSystemServer() {
         if (this instanceof DeadObjectException) {
             throw new RuntimeException(new DeadSystemException());
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index c707ba8..0bf634e 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1892,6 +1892,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public static void conditionallyCheckInstanceCounts() {
         VmPolicy policy = getVmPolicy();
@@ -2751,6 +2752,7 @@
         }
 
         /** Create an instance of ViolationInfo initialized from a Parcel. */
+        @UnsupportedAppUsage
         public ViolationInfo(Parcel in) {
             this(in, false);
         }
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 3558fcd..537cb98 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -198,6 +198,7 @@
      * "it's system", because of isolated UIDs. Use {@link #isCore} for that.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static boolean isApp(int uid) {
         if (uid > 0) {
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 26da0a0..5769c34 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -27,6 +27,8 @@
 import android.net.Uri;
 import android.util.MathUtils;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
@@ -77,6 +79,7 @@
      * @see #get(int)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int EFFECT_THUD = Effect.THUD;
 
@@ -85,6 +88,7 @@
      * @see #get(int)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int EFFECT_POP = Effect.POP;
 
@@ -126,6 +130,7 @@
      * @see #get(Uri, Context)
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int[] RINGTONES = {
         Effect.RINGTONE_1,
@@ -493,6 +498,7 @@
             out.writeInt(mAmplitude);
         }
 
+        @UnsupportedAppUsage
         public static final @android.annotation.NonNull Parcelable.Creator<OneShot> CREATOR =
             new Parcelable.Creator<OneShot>() {
                 @Override
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 9cc9aac..825fc64 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -92,6 +92,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public WorkSource(int uid) {
         mNum = 1;
@@ -138,12 +139,14 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public int size() {
         return mNum;
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public int get(int index) {
         return mUids[index];
@@ -165,6 +168,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public String getName(int index) {
         return mNames != null ? mNames[index] : null;
@@ -419,6 +423,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public boolean add(int uid) {
         if (mNum <= 0) {
@@ -439,6 +444,7 @@
     }
 
     /** @hide */
+    @UnsupportedAppUsage
     @TestApi
     public boolean add(int uid, String name) {
         if (mNum <= 0) {
diff --git a/core/java/android/os/health/HealthStatsParceler.java b/core/java/android/os/health/HealthStatsParceler.java
index de98359..384342c 100644
--- a/core/java/android/os/health/HealthStatsParceler.java
+++ b/core/java/android/os/health/HealthStatsParceler.java
@@ -19,10 +19,8 @@
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.ArrayMap;
 
-import java.util.Arrays;
-import java.util.Map;
+import dalvik.annotation.compat.UnsupportedAppUsage;
 
 /**
  * Class to allow sending the HealthStats through aidl generated glue.
@@ -41,6 +39,7 @@
     private HealthStatsWriter mWriter;
     private HealthStats mHealthStats;
 
+    @UnsupportedAppUsage
     public static final @android.annotation.NonNull Parcelable.Creator<HealthStatsParceler> CREATOR
             = new Parcelable.Creator<HealthStatsParceler>() {
         public HealthStatsParceler createFromParcel(Parcel in) {
diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java
index 0e00d5e..4c92c28 100644
--- a/core/java/android/os/image/DynamicSystemManager.java
+++ b/core/java/android/os/image/DynamicSystemManager.java
@@ -101,6 +101,19 @@
         }
     }
     /**
+     * Start DynamicSystem installation.
+     *
+     * @return true if the call succeeds
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+    public boolean startInstallation() {
+        try {
+            return mService.startInstallation();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+    /**
      * Start DynamicSystem installation. This call may take an unbounded amount of time. The caller
      * may use another thread to call the getStartProgress() to get the progress.
      *
@@ -112,9 +125,9 @@
      *     true.
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
-    public Session startInstallation(String name, long size, boolean readOnly) {
+    public Session createPartition(String name, long size, boolean readOnly) {
         try {
-            if (mService.startInstallation(name, size, readOnly)) {
+            if (mService.createPartition(name, size, readOnly)) {
                 return new Session();
             } else {
                 return null;
@@ -123,7 +136,18 @@
             throw new RuntimeException(e.toString());
         }
     }
-
+    /**
+     * Finish a previously started installation. Installations without a cooresponding
+     * finishInstallation() will be cleaned up during device boot.
+     */
+    @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM)
+    public boolean finishInstallation() {
+        try {
+            return mService.finishInstallation();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
     /**
      * Query the progress of the current installation operation. This can be called while the
      * installation is in progress.
diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl
index 75f6785..69cbab2 100644
--- a/core/java/android/os/image/IDynamicSystemService.aidl
+++ b/core/java/android/os/image/IDynamicSystemService.aidl
@@ -21,15 +21,26 @@
 interface IDynamicSystemService
 {
     /**
-     * Start DynamicSystem installation. This call may take 60~90 seconds. The caller
+     * Start DynamicSystem installation.
+     * @return true if the call succeeds
+     */
+    boolean startInstallation();
+
+    /**
+     * Create a DSU partition. This call may take 60~90 seconds. The caller
      * may use another thread to call the getStartProgress() to get the progress.
-     *
      * @param name The DSU partition name
      * @param size Size of the DSU image in bytes
      * @param readOnly True if this partition is readOnly
      * @return true if the call succeeds
      */
-    boolean startInstallation(@utf8InCpp String name, long size, boolean readOnly);
+    boolean createPartition(@utf8InCpp String name, long size, boolean readOnly);
+
+    /**
+     * Finish a previously started installation. Installations without
+     * a cooresponding finishInstallation() will be cleaned up during device boot.
+     */
+    boolean finishInstallation();
 
     /**
      * Query the progress of the current installation operation. This can be called while
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/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 6280600..aefe843 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -173,6 +173,7 @@
      * @return the mount path
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public String getPath() {
         return mPath.toString();
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/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index d862d602..7285166 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -1862,6 +1862,7 @@
          *
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
             _SYNC_ID,
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index c91d42b..2cb0750 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -227,7 +227,7 @@
 
         /**
          * Indicates the call underwent Assisted Dialing.
-         * @hide
+         * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
          */
         public static final int FEATURES_ASSISTED_DIALING_USED = 1 << 4;
 
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index af3a16c..f10e184 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -126,6 +126,7 @@
      * Prefix for column names that are not visible to client apps.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final String HIDDEN_COLUMN_PREFIX = "x_";
 
@@ -6069,6 +6070,7 @@
             *
             * @hide
             */
+            @UnsupportedAppUsage
             @TestApi
             public static final Uri ENTERPRISE_CONTENT_URI =
                     Uri.withAppendedPath(Data.ENTERPRISE_CONTENT_URI, "phones");
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index aa67d97..01f9c73 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -104,7 +104,14 @@
     /** The authority for the media provider */
     public static final String AUTHORITY = "media";
     /** A content:// style uri to the authority for the media provider */
-    public static final @NonNull Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+    public static final @NonNull Uri AUTHORITY_URI =
+            Uri.parse("content://" + AUTHORITY);
+
+    /** @hide */
+    public static final String AUTHORITY_LEGACY = "media_legacy";
+    /** @hide */
+    public static final @NonNull Uri AUTHORITY_LEGACY_URI =
+            Uri.parse("content://" + AUTHORITY_LEGACY);
 
     /**
      * Synthetic volume name that provides a view of all content across the
@@ -878,6 +885,16 @@
     }
 
     /**
+     * Rewrite the given {@link Uri} to point at
+     * {@link MediaStore#AUTHORITY_LEGACY}.
+     *
+     * @hide
+     */
+    public static @NonNull Uri rewriteToLegacy(@NonNull Uri uri) {
+        return uri.buildUpon().authority(MediaStore.AUTHORITY_LEGACY).build();
+    }
+
+    /**
      * Common media metadata columns.
      */
     public interface MediaColumns extends BaseColumns {
@@ -3477,11 +3494,15 @@
      */
     public static @NonNull String getVolumeName(@NonNull Uri uri) {
         final List<String> segments = uri.getPathSegments();
-        if (uri.getAuthority().equals(AUTHORITY) && segments != null && segments.size() > 0) {
-            return segments.get(0);
-        } else {
-            throw new IllegalArgumentException("Missing volume name: " + uri);
+        switch (uri.getAuthority()) {
+            case AUTHORITY:
+            case AUTHORITY_LEGACY: {
+                if (segments != null && segments.size() > 0) {
+                    return segments.get(0);
+                }
+            }
         }
+        throw new IllegalArgumentException("Missing volume name: " + uri);
     }
 
     /** {@hide} */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 350cb0a..50dac46 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -836,9 +836,9 @@
      * In some cases, a matching Activity may not exist, so ensure you
      * safeguard against this.
      * <p>
-     * Input: Optionally, the Intent's data URI can specify the application package name to
-     * directly invoke the management GUI specific to the package name. For example
-     * "package:com.my.app".
+     * Input: Optionally, in versions of Android prior to 11, the Intent's data URI can specify the
+     * application package name to directly invoke the management GUI specific to the package name.
+     * For example "package:com.my.app".
      * <p>
      * Output: Nothing.
      */
@@ -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
@@ -2060,6 +2087,7 @@
      * This is the only type of reset available to non-system clients.
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static final int RESET_MODE_PACKAGE_DEFAULTS = 1;
 
@@ -6137,6 +6165,7 @@
          * shortcut. Must be its flattened {@link ComponentName}.
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
                 "accessibility_shortcut_target_service";
@@ -6294,6 +6323,7 @@
          *
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED =
                 "accessibility_display_magnification_enabled";
@@ -7944,6 +7974,7 @@
          *
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
 
@@ -8091,6 +8122,7 @@
          * The value is boolean (1 or 0).
          * @hide
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String NOTIFICATION_BADGING = "notification_badging";
 
@@ -8357,7 +8389,6 @@
 
             INSTANT_APP_SETTINGS.add(ANDROID_ID);
 
-            INSTANT_APP_SETTINGS.add(PACKAGE_VERIFIER_USER_CONSENT);
             INSTANT_APP_SETTINGS.add(ALLOW_MOCK_LOCATION);
         }
 
@@ -10067,25 +10098,26 @@
         */
        public static final String MODE_RINGER = "mode_ringer";
 
-       /**
-        * Overlay display devices setting.
-        * The associated value is a specially formatted string that describes the
-        * size and density of simulated secondary display devices.
-        * <p>
-        * Format: {width}x{height}/{dpi};...
-        * </p><p>
-        * Example:
-        * <ul>
-        * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
-        * <li><code>1920x1080/320;1280x720/213</code>: make two overlays, the first
-        * at 1080p and the second at 720p.</li>
-        * <li>If the value is empty, then no overlay display devices are created.</li>
-        * </ul></p>
-        *
-        * @hide
-        */
-       @TestApi
-       public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
+        /**
+         * Overlay display devices setting.
+         * The associated value is a specially formatted string that describes the
+         * size and density of simulated secondary display devices.
+         * <p>
+         * Format: {width}x{height}/{dpi};...
+         * </p><p>
+         * Example:
+         * <ul>
+         * <li><code>1280x720/213</code>: make one overlay that is 1280x720 at 213dpi.</li>
+         * <li><code>1920x1080/320;1280x720/213</code>: make two overlays, the first
+         * at 1080p and the second at 720p.</li>
+         * <li>If the value is empty, then no overlay display devices are created.</li>
+         * </ul></p>
+         *
+         * @hide
+         */
+        @UnsupportedAppUsage
+        @TestApi
+        public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
 
         /**
          * Threshold values for the duration and level of a discharge cycle,
@@ -10734,6 +10766,7 @@
          * @hide
          * @see com.android.server.power.batterysaver.BatterySaverPolicy
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final String BATTERY_SAVER_CONSTANTS = "battery_saver_constants";
 
diff --git a/core/java/android/service/euicc/EuiccService.java b/core/java/android/service/euicc/EuiccService.java
index 12c2580..bc6a9e8 100644
--- a/core/java/android/service/euicc/EuiccService.java
+++ b/core/java/android/service/euicc/EuiccService.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.Intent;
@@ -104,6 +105,26 @@
             "android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE";
 
     /**
+     * Intent action sent by the LPA to launch a carrier app Activity for eSIM activation, e.g. a
+     * carrier login screen. Carrier apps wishing to support this activation method must implement
+     * an Activity that responds to this intent action. Upon completion, the Activity must return
+     * one of the following results to the LPA:
+     *
+     * <p>{@code Activity.RESULT_CANCELED}: The LPA should treat this as an back button and abort
+     * the activation flow.
+     * <p>{@code Activity.RESULT_OK}: The LPA should try to get an activation code from the carrier
+     * app by binding to the carrier app service implementing
+     * {@link #ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
+     * <p>{@code Activity.RESULT_OK} with
+     * {@link android.telephony.euicc.EuiccManager#EXTRA_USE_QR_SCANNER} set to true: The LPA should
+     * start a QR scanner for the user to scan an eSIM profile QR code.
+     * <p>For other results: The LPA should treat this as an error.
+     **/
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_START_CARRIER_ACTIVATION =
+            "android.service.euicc.action.START_CARRIER_ACTIVATION";
+
+    /**
      * @see android.telephony.euicc.EuiccManager#ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS
      * The difference is this one is used by system to bring up the LUI.
      */
@@ -138,6 +159,15 @@
     public static final String ACTION_RENAME_SUBSCRIPTION_PRIVILEGED =
             "android.service.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
 
+    /**
+     * @see android.telephony.euicc.EuiccManager#ACTION_START_EUICC_ACTIVATION. This is
+     * a protected intent that can only be sent by the system, and requires the
+     * {@link android.Manifest.permission#BIND_EUICC_SERVICE} permission.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_START_EUICC_ACTIVATION =
+            "android.service.euicc.action.START_EUICC_ACTIVATION";
+
     // LUI resolution actions. These are called by the platform to resolve errors in situations that
     // require user interaction.
     // TODO(b/33075886): Define extras for any input parameters to these dialogs once they are
@@ -516,7 +546,7 @@
      * @see android.telephony.euicc.EuiccManager#eraseSubscriptions
      *
      * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
-     * and use {@link #onEraseSubscriptionsWithOptions(int, int)} instead
+     * and use {@link #onEraseSubscriptions(int, int)} instead
      */
     @Deprecated
     public abstract int onEraseSubscriptions(int slotId);
@@ -533,7 +563,7 @@
      *     constants or any implementation-specific code starting with {@link #RESULT_FIRST_USER}.
      * @see android.telephony.euicc.EuiccManager#eraseSubscriptionsWithOptions
      */
-    public int onEraseSubscriptionsWithOptions(int slotIndex, @ResetOption int options) {
+    public int onEraseSubscriptions(int slotIndex, @ResetOption int options) {
         throw new UnsupportedOperationException(
                 "This method must be overridden to enable the ResetOption parameter");
     }
@@ -779,8 +809,7 @@
             mExecutor.execute(new Runnable() {
                 @Override
                 public void run() {
-                    int result = EuiccService.this.onEraseSubscriptionsWithOptions(
-                            slotIndex, options);
+                    int result = EuiccService.this.onEraseSubscriptions(slotIndex, options);
                     try {
                         callback.onComplete(result);
                     } catch (RemoteException e) {
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/telephony/java/android/telephony/Rlog.java b/core/java/android/telephony/Rlog.java
similarity index 100%
rename from telephony/java/android/telephony/Rlog.java
rename to core/java/android/telephony/Rlog.java
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 7c7223c..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 {
     /**
@@ -245,7 +244,7 @@
      * this density value will be 1; on a 120 dpi screen it would be .75; etc.
      *  
      * <p>This value does not exactly follow the real screen size (as given by 
-     * {@link #xdpi} and {@link #ydpi}, but rather is used to scale the size of
+     * {@link #xdpi} and {@link #ydpi}), but rather is used to scale the size of
      * the overall UI in steps based on gross changes in the display dpi.  For 
      * example, a 240x320 screen will have a density of 1 even if its width is 
      * 1.8", 1.3", etc. However, if the screen resolution is increased to 
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.aidl b/core/java/android/util/StatsEvent.aidl
new file mode 100644
index 0000000..deac873
--- /dev/null
+++ b/core/java/android/util/StatsEvent.aidl
@@ -0,0 +1,19 @@
+/**
+ * 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.util;
+
+parcelable StatsEvent cpp_header "android/util/StatsEvent.h";
diff --git a/core/java/android/util/StatsEvent.java b/core/java/android/util/StatsEvent.java
index a21f9e0..10c9d87 100644
--- a/core/java/android/util/StatsEvent.java
+++ b/core/java/android/util/StatsEvent.java
@@ -20,6 +20,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.SystemClock;
 
 import com.android.internal.annotations.GuardedBy;
@@ -42,7 +44,7 @@
  * </pre>
  * @hide
  **/
-public final class StatsEvent {
+public final class StatsEvent implements Parcelable {
     private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;
 
     // Max payload size is 4 bytes less as 4 bytes are reserved for statsEventTag.
@@ -63,7 +65,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());
     }
 
@@ -631,4 +633,39 @@
             return 0;
         }
     }
+
+    /**
+     * Boilerplate for Parcel.
+     *
+     * @hide
+     */
+    public static final @NonNull Parcelable.Creator<StatsEvent> CREATOR =
+            new Parcelable.Creator<StatsEvent>() {
+                public StatsEvent createFromParcel(Parcel in) {
+                    // Purposefully leaving this method not implemented.
+                    throw new RuntimeException("Not implemented");
+                }
+
+                public StatsEvent[] newArray(int size) {
+                    // Purposefully leaving this method not implemented.
+                    throw new RuntimeException("Not implemented");
+                }
+            };
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mAtomId);
+        out.writeInt(getNumBytes());
+        out.writeByteArray(getBytes());
+    }
+
+    /**
+     * Boilerplate for Parcel.
+     */
+    public int describeContents() {
+        return 0;
+    }
+
 }
diff --git a/core/java/android/view/ActionMode.java b/core/java/android/view/ActionMode.java
index 05d9167..6b200e1 100644
--- a/core/java/android/view/ActionMode.java
+++ b/core/java/android/view/ActionMode.java
@@ -21,6 +21,8 @@
 import android.annotation.TestApi;
 import android.graphics.Rect;
 
+import dalvik.annotation.compat.UnsupportedAppUsage;
+
 /**
  * Represents a contextual mode of the user interface. Action modes can be used to provide
  * alternative interaction modes and replace parts of the normal UI until finished.
@@ -279,6 +281,7 @@
      * @return true if the UI used to show this action mode can take focus
      * @hide Internal use only
      */
+    @UnsupportedAppUsage
     @TestApi
     public boolean isUiFocusable() {
         return true;
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index e95b5ca..28eb79a 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -331,6 +331,7 @@
      * @return the requested time between frames, in milliseconds
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public static long getFrameDelay() {
         return sFrameDelay;
@@ -413,6 +414,7 @@
      * @see #removeCallbacks
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public void postCallback(int callbackType, Runnable action, Object token) {
         postCallbackDelayed(callbackType, action, token, 0);
@@ -432,6 +434,7 @@
      * @see #removeCallback
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public void postCallbackDelayed(int callbackType,
             Runnable action, Object token, long delayMillis) {
@@ -482,6 +485,7 @@
      * @see #postCallbackDelayed
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public void removeCallbacks(int callbackType, Runnable action, Object token) {
         if (callbackType < 0 || callbackType > CALLBACK_LAST) {
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/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 1fc7f0e..75862e0 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -62,19 +62,20 @@
  * {@link Context#getSystemService} to retrieve a standard LayoutInflater instance
  * that is already hooked up to the current context and correctly configured
  * for the device you are running on.
- *
  * <p>
  * To create a new LayoutInflater with an additional {@link Factory} for your
  * own views, you can use {@link #cloneInContext} to clone an existing
  * ViewFactory, and then call {@link #setFactory} on it to include your
  * Factory.
- *
  * <p>
  * For performance reasons, view inflation relies heavily on pre-processing of
  * XML files that is done at build time. Therefore, it is not currently possible
  * to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
  * it only works with an XmlPullParser returned from a compiled resource
  * (R.<em>something</em> file.)
+ * <p>
+ * <strong>Note:</strong> This class is <strong>not</strong> thread-safe and a given
+ * instance should only be accessed by a single thread.
  */
 @SystemService(Context.LAYOUT_INFLATER_SERVICE)
 public abstract class LayoutInflater {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index bd865c0..be4c598 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2610,6 +2610,7 @@
      * @see #getActionButton()
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public final void setActionButton(int button) {
         nativeSetActionButton(mNativePtr, button);
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8dd475e..3251127 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -90,7 +90,8 @@
             Rect sourceCrop, int width, int height, boolean useIdentityTransform, int rotation,
             boolean captureSecureLayers);
     private static native ScreenshotGraphicBuffer nativeCaptureLayers(IBinder displayToken,
-            long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects);
+            long layerObject, Rect sourceCrop, float frameScale, long[] excludeLayerObjects,
+            int format);
     private static native long nativeMirrorSurface(long mirrorOfObject);
     private static native long nativeCreateTransaction();
     private static native long nativeGetNativeTransactionFinalizer();
@@ -196,6 +197,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;
@@ -1867,8 +1870,27 @@
      */
     public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
             float frameScale) {
+        return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
+    }
+
+    /**
+     * Captures a layer and its children and returns a {@link GraphicBuffer} with the content.
+     *
+     * @param layer            The root layer to capture.
+     * @param sourceCrop       The portion of the root surface to capture; caller may pass in 'new
+     *                         Rect()' or null if no cropping is desired.
+     * @param frameScale       The desired scale of the returned buffer; the raw
+     *                         screen will be scaled up/down.
+     * @param format           The desired pixel format of the returned buffer.
+     *
+     * @return Returns a GraphicBuffer that contains the layer capture.
+     * @hide
+     */
+    public static ScreenshotGraphicBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
+            float frameScale, int format) {
         final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
-        return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null);
+        return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale, null,
+                format);
     }
 
     /**
@@ -1883,7 +1905,7 @@
             nativeExcludeObjects[i] = exclude[i].mNativeObject;
         }
         return nativeCaptureLayers(displayToken, layer.mNativeObject, sourceCrop, frameScale,
-                nativeExcludeObjects);
+                nativeExcludeObjects, PixelFormat.RGBA_8888);
     }
 
     /**
@@ -2545,6 +2567,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 412b0ca..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}.
@@ -24729,6 +24714,7 @@
      * @param isRoot true if the view belongs to the root namespace, false
      *        otherwise
      */
+    @UnsupportedAppUsage
     @TestApi
     public void setIsRootNamespace(boolean isRoot) {
         if (isRoot) {
@@ -26414,7 +26400,7 @@
 
     /**
      * Returns the over-scroll mode for this view. The result will be
-     * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
+     * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
      * (allow over-scrolling only if the view content is larger than the container),
      * or {@link #OVER_SCROLL_NEVER}.
      *
@@ -26431,7 +26417,7 @@
 
     /**
      * Set the over-scroll mode for this view. Valid over-scroll modes are
-     * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
+     * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
      * (allow over-scrolling only if the view content is larger than the container),
      * or {@link #OVER_SCROLL_NEVER}.
      *
@@ -28444,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.
          */
@@ -28477,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.
@@ -28591,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/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 6a099d57..9e914d4 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.os.Build;
 import android.os.RemoteException;
 import android.provider.Settings;
@@ -397,7 +398,11 @@
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
 
         // Size of the screen in bytes, in ARGB_8888 format
-        mMaximumDrawingCacheSize = 4 * metrics.heightPixels * metrics.widthPixels;
+        final WindowManager win = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        final Display display = win.getDefaultDisplay();
+        final Point size = new Point();
+        display.getRealSize(size);
+        mMaximumDrawingCacheSize = 4 * size.x * size.y;
 
         mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
@@ -837,7 +842,6 @@
      * The maximum drawing cache size expressed in bytes.
      *
      * @return the maximum size of View's drawing cache expressed in bytes
-     *
      */
     public int getScaledMaximumDrawingCacheSize() {
         return mMaximumDrawingCacheSize;
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/Window.java b/core/java/android/view/Window.java
index fa2dbc9..c699cdc 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -127,7 +127,10 @@
     public static final int FEATURE_ACTION_MODE_OVERLAY = 10;
     /**
      * Flag for requesting a decoration-free window that is dismissed by swiping from the left.
+     *
+     * @deprecated Swipe-to-dismiss isn't functional anymore.
      */
+    @Deprecated
     public static final int FEATURE_SWIPE_TO_DISMISS = 11;
     /**
      * Flag for requesting that window content changes should be animated using a
@@ -2522,23 +2525,6 @@
     public abstract void reportActivityRelaunched();
 
     /**
-     * Called to set flag to check if the close on swipe is enabled. This will only function if
-     * FEATURE_SWIPE_TO_DISMISS has been set.
-     * @hide
-     */
-    public void setCloseOnSwipeEnabled(boolean closeOnSwipeEnabled) {
-        mCloseOnSwipeEnabled = closeOnSwipeEnabled;
-    }
-
-    /**
-     * @return {@code true} if the close on swipe is enabled.
-     * @hide
-     */
-    public boolean isCloseOnSwipeEnabled() {
-        return mCloseOnSwipeEnabled;
-    }
-
-    /**
      * @return The {@link WindowInsetsController} associated with this window
      * @see View#getWindowInsetsController()
      * @hide pending unhide
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index db76bb6..c62e69c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1181,8 +1181,7 @@
          * a soft input method, so it will be Z-ordered and positioned
          * independently of any active input method (typically this means it
          * gets Z-ordered on top of the input method, so it can use the full
-         * screen for its content and cover the input method if needed.  You
-         * can use {@link #FLAG_ALT_FOCUSABLE_IM} to modify this behavior. */
+         * screen for its content and cover the input method if needed.) */
         public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
 
         /** Window flag: this window can never receive touch events. */
@@ -1288,14 +1287,11 @@
          * set for you by Window as described in {@link Window#setFlags}.*/
         public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
 
-        /** Window flag: invert the state of {@link #FLAG_NOT_FOCUSABLE} with
-         * respect to how this window interacts with the current method.  That
-         * is, if FLAG_NOT_FOCUSABLE is set and this flag is set, then the
-         * window will behave as if it needs to interact with the input method
-         * and thus be placed behind/away from it; if FLAG_NOT_FOCUSABLE is
-         * not set and this flag is set, then the window will behave as if it
-         * doesn't need to interact with the input method and can be placed
-         * to use more space and cover the input method.
+        /** Window flag: When set, input method can't interact with the focusable window
+         * and can be placed to use more space and cover the input method.
+         * Note: When combined with {@link #FLAG_NOT_FOCUSABLE}, this flag has no
+         * effect since input method cannot interact with windows having {@link #FLAG_NOT_FOCUSABLE}
+         * flag set.
          */
         public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
 
@@ -1449,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;
 
         /**
@@ -1689,6 +1688,7 @@
          *
          * {@hide}
          */
+        @UnsupportedAppUsage
         @TestApi
         public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
 
@@ -1705,11 +1705,6 @@
          * {@hide} */
         public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
 
-        /** Window flag: maintain the previous translucent decor state when this window
-         * becomes top-most.
-         * {@hide} */
-        public static final int PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR = 0x00000200;
-
         /**
          * Flag whether the current window is a keyguard window, meaning that it will hide all other
          * windows behind it except for windows with flag {@link #FLAG_SHOW_WHEN_LOCKED} set.
@@ -1851,6 +1846,7 @@
          * Control flags that are private to the platform.
          * @hide
          */
+        @UnsupportedAppUsage
         @ViewDebug.ExportedProperty(flagMapping = {
                 @ViewDebug.FlagToString(
                         mask = PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED,
@@ -1881,10 +1877,6 @@
                         equals = PRIVATE_FLAG_SYSTEM_ERROR,
                         name = "SYSTEM_ERROR"),
                 @ViewDebug.FlagToString(
-                        mask = PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR,
-                        equals = PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR,
-                        name = "INHERIT_TRANSLUCENT_DECOR"),
-                @ViewDebug.FlagToString(
                         mask = PRIVATE_FLAG_KEYGUARD,
                         equals = PRIVATE_FLAG_KEYGUARD,
                         name = "KEYGUARD"),
@@ -1997,16 +1989,12 @@
          *
          * @param flags The current window manager flags.
          *
-         * @return Returns true if such a window should be behind/interact
-         * with an input method, false if not.
+         * @return Returns {@code true} if such a window should be behind/interact
+         * with an input method, (@code false} if not.
          */
         public static boolean mayUseInputMethod(int flags) {
-            switch (flags&(FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM)) {
-                case 0:
-                case FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM:
-                    return true;
-            }
-            return false;
+            return (flags & FLAG_NOT_FOCUSABLE) != FLAG_NOT_FOCUSABLE
+                    && (flags & FLAG_ALT_FOCUSABLE_IM) != FLAG_ALT_FOCUSABLE_IM;
         }
 
         /**
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/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index b33fdbb..a389555 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -4590,10 +4590,6 @@
          * @param label The label for the new AccessibilityAction.
          */
         public AccessibilityAction(int actionId, @Nullable CharSequence label) {
-            if ((actionId & ACTION_TYPE_MASK) == 0 && Integer.bitCount(actionId) != 1) {
-                throw new IllegalArgumentException("Invalid standard action id");
-            }
-
             mActionId = actionId;
             mLabel = label;
         }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 090e19f..ae2fb8e 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -211,6 +211,10 @@
      *        If this is greater than the number of existing characters between the cursor and
      *        the end of the text, then this method does not fail but deletes all the characters in
      *        that range.
+     *
+     * @return {@code true} when selected text is deleted, {@code false} when either the
+     *         selection is invalid or not yet attached (i.e. selection start or end is -1),
+     *         or the editable text is {@code null}.
      */
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         if (DEBUG) Log.v(TAG, "deleteSurroundingText " + beforeLength
@@ -229,6 +233,12 @@
             b = tmp;
         }
 
+        // Skip when the selection is not yet attached.
+        if (a == -1 || b == -1) {
+            endBatchEdit();
+            return false;
+        }
+
         // Ignore the composing text.
         int ca = getComposingSpanStart(content);
         int cb = getComposingSpanEnd(content);
@@ -247,8 +257,12 @@
         if (beforeLength > 0) {
             int start = a - beforeLength;
             if (start < 0) start = 0;
-            content.delete(start, a);
-            deleted = a - start;
+
+            final int numDeleteBefore = a - start;
+            if (a >= 0 && numDeleteBefore > 0) {
+                content.delete(start, a);
+                deleted = numDeleteBefore;
+            }
         }
 
         if (afterLength > 0) {
@@ -257,7 +271,10 @@
             int end = b + afterLength;
             if (end > content.length()) end = content.length();
 
-            content.delete(b, end);
+            final int numDeleteAfter = end - b;
+            if (b >= 0 && numDeleteAfter > 0) {
+                content.delete(b, end);
+            }
         }
 
         endBatchEdit();
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e81db16..2650a67 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -655,14 +655,14 @@
                             } catch (RemoteException e) {
                             }
                         }
-                        // Check focus again in case that "onWindowFocus" is called before
-                        // handling this message.
-                        if (mServedView != null && canStartInput(mServedView)) {
-                            if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) {
-                                final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
-                                        : StartInputReason.DEACTIVATED_BY_IMMS;
-                                startInputInner(reason, null, 0, 0, 0);
-                            }
+                    }
+                    // Check focus again in case that "onWindowFocus" is called before
+                    // handling this message.
+                    if (mServedView != null && canStartInput(mServedView)) {
+                        if (checkFocusNoStartInput(mRestartOnNextWindowFocus)) {
+                            final int reason = active ? StartInputReason.ACTIVATED_BY_IMMS
+                                    : StartInputReason.DEACTIVATED_BY_IMMS;
+                            startInputInner(reason, null, 0, 0, 0);
                         }
                     }
                     return;
@@ -1225,6 +1225,10 @@
      */
     void clearBindingLocked() {
         if (DEBUG) Log.v(TAG, "Clearing binding!");
+        if (mWindowFocusGainFuture != null) {
+            mWindowFocusGainFuture.cancel(false /* mayInterruptIfRunning */);
+            mWindowFocusGainFuture = null;
+        }
         clearConnectionLocked();
         setInputChannelLocked(null);
         mBindSequence = -1;
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/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index b1752a4..6c372e4 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -96,10 +96,7 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.DecelerateInterpolator;
-import android.widget.AbsListView;
-import android.widget.BaseAdapter;
 import android.widget.ImageView;
-import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
 
@@ -118,6 +115,8 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.util.ImageUtils;
+import com.android.internal.widget.GridLayoutManager;
+import com.android.internal.widget.RecyclerView;
 import com.android.internal.widget.ResolverDrawerLayout;
 
 import com.google.android.collect.Lists;
@@ -167,6 +166,7 @@
 
     @VisibleForTesting
     public static final int LIST_VIEW_UPDATE_INTERVAL_IN_MILLIS = 250;
+    private static final int SINGLE_CELL_SPAN_SIZE = 1;
 
     private boolean mIsAppPredictorComponentAvailable;
     private AppPredictor mAppPredictor;
@@ -222,8 +222,9 @@
     private long mQueriedTargetServicesTimeMs;
     private long mQueriedSharingShortcutsTimeMs;
 
+    private RecyclerView mRecyclerView;
     private ChooserListAdapter mChooserListAdapter;
-    private ChooserRowAdapter mChooserRowAdapter;
+    private ChooserGridAdapter mChooserGridAdapter;
     private int mChooserRowServiceSpacing;
 
     private int mCurrAvailableWidth = 0;
@@ -351,8 +352,8 @@
                 Log.i(TAG, "Hiding image preview area. Timed out waiting for preview to load"
                         + " within " + mImageLoadTimeoutMillis + "ms.");
                 collapseParentView();
-                if (mChooserRowAdapter != null) {
-                    mChooserRowAdapter.hideContentPreview();
+                if (mChooserGridAdapter != null) {
+                    mChooserGridAdapter.hideContentPreview();
                 }
                 mHideParentOnFail = false;
             }
@@ -671,14 +672,14 @@
             final float chooserHeaderScrollElevation =
                     getResources().getDimensionPixelSize(R.dimen.chooser_header_scroll_elevation);
 
-            mAdapterView.setOnScrollListener(new AbsListView.OnScrollListener() {
-                public void onScrollStateChanged(AbsListView view, int scrollState) {
+            mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
+                public void onScrollStateChanged(RecyclerView view, int scrollState) {
                 }
 
-                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
-                        int totalItemCount) {
+                public void onScrolled(RecyclerView view, int dx, int dy) {
                     if (view.getChildCount() > 0) {
-                        if (firstVisibleItem > 0 || view.getChildAt(0).getTop() < 0) {
+                        View child = view.getLayoutManager().findViewByPosition(0);
+                        if (child == null || child.getTop() < 0) {
                             chooserHeader.setElevation(chooserHeaderScrollElevation);
                             return;
                         }
@@ -847,10 +848,7 @@
     }
 
     private ViewGroup displayContentPreview(@ContentPreviewType int previewType,
-            Intent targetIntent, LayoutInflater layoutInflater, ViewGroup convertView,
-            ViewGroup parent) {
-        if (convertView != null) return convertView;
-
+            Intent targetIntent, LayoutInflater layoutInflater, ViewGroup parent) {
         ViewGroup layout = null;
 
         switch (previewType) {
@@ -1213,22 +1211,36 @@
     }
 
     @Override
-    public void onPrepareAdapterView(AbsListView adapterView, ResolverListAdapter adapter) {
-        final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
+    public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
+        mRecyclerView = findViewById(R.id.resolver_list);
+        if (!isVisible) {
+            mRecyclerView.setVisibility(View.GONE);
+            return;
+        }
+        mRecyclerView.setVisibility(View.VISIBLE);
         if (mCallerChooserTargets != null && mCallerChooserTargets.length > 0) {
             mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets),
                     TARGET_TYPE_DEFAULT);
         }
-        mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
-        if (listView != null) {
-            listView.setItemsCanFocus(true);
-        }
+        mChooserGridAdapter = new ChooserGridAdapter(mChooserListAdapter);
+        GridLayoutManager glm = (GridLayoutManager) mRecyclerView.getLayoutManager();
+        glm.setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
+        glm.setSpanSizeLookup(
+                new GridLayoutManager.SpanSizeLookup() {
+                    @Override
+                    public int getSpanSize(int position) {
+                        return mChooserGridAdapter.getItemViewType(position)
+                                == ChooserGridAdapter.VIEW_TYPE_NORMAL
+                                ? SINGLE_CELL_SPAN_SIZE
+                                : glm.getSpanCount();
+                    }
+                });
     }
 
     @Override
-    protected boolean rebuildList() {
+    protected boolean postRebuildList(boolean rebuildCompleted) {
         mChooserListAdapter = (ChooserListAdapter) mAdapter;
-        return rebuildListInternal();
+        return postRebuildListInternal(rebuildCompleted);
     }
 
     @Override
@@ -1996,8 +2008,8 @@
     }
 
     private void handleScroll(View view, int x, int y, int oldx, int oldy) {
-        if (mChooserRowAdapter != null) {
-            mChooserRowAdapter.handleScroll(view, y, oldy);
+        if (mChooserGridAdapter != null) {
+            mChooserGridAdapter.handleScroll(view, y, oldy);
         }
     }
 
@@ -2008,35 +2020,37 @@
      */
     private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
-        if (mChooserRowAdapter == null || mAdapterView == null) {
+        if (mChooserGridAdapter == null || mRecyclerView == null) {
             return;
         }
 
         final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
-        if (mChooserRowAdapter.consumeLayoutRequest()
-                || mChooserRowAdapter.calculateChooserTargetWidth(availableWidth)
-                || mAdapterView.getAdapter() == null
+        if (mChooserGridAdapter.consumeLayoutRequest()
+                || mChooserGridAdapter.calculateChooserTargetWidth(availableWidth)
+                || mRecyclerView.getAdapter() == null
                 || availableWidth != mCurrAvailableWidth) {
             mCurrAvailableWidth = availableWidth;
-            mAdapterView.setAdapter(mChooserRowAdapter);
+            mRecyclerView.setAdapter(mChooserGridAdapter);
+            ((GridLayoutManager) mRecyclerView.getLayoutManager())
+                    .setSpanCount(mChooserGridAdapter.getMaxTargetsPerRow());
 
             getMainThreadHandler().post(() -> {
-                if (mResolverDrawerLayout == null || mChooserRowAdapter == null) {
+                if (mResolverDrawerLayout == null || mChooserGridAdapter == null) {
                     return;
                 }
 
                 final int bottomInset = mSystemWindowInsets != null
                                             ? mSystemWindowInsets.bottom : 0;
                 int offset = bottomInset;
-                int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
-                        + mChooserRowAdapter.getProfileRowCount()
-                        + mChooserRowAdapter.getServiceTargetRowCount()
-                        + mChooserRowAdapter.getCallerAndRankedTargetRowCount();
+                int rowsToShow = mChooserGridAdapter.getContentPreviewRowCount()
+                        + mChooserGridAdapter.getProfileRowCount()
+                        + mChooserGridAdapter.getServiceTargetRowCount()
+                        + mChooserGridAdapter.getCallerAndRankedTargetRowCount();
 
                 // then this is most likely not a SEND_* action, so check
                 // the app target count
                 if (rowsToShow == 0) {
-                    rowsToShow = mChooserRowAdapter.getCount();
+                    rowsToShow = mChooserGridAdapter.getRowCount();
                 }
 
                 // still zero? then use a default height and leave, which
@@ -2050,15 +2064,22 @@
 
                 int directShareHeight = 0;
                 rowsToShow = Math.min(4, rowsToShow);
-                for (int i = 0; i < Math.min(rowsToShow, mAdapterView.getChildCount()); i++) {
-                    View child = mAdapterView.getChildAt(i);
+                for (int i = 0, childCount = mRecyclerView.getChildCount();
+                        i < childCount && rowsToShow > 0; i++) {
+                    View child = mRecyclerView.getChildAt(i);
+                    if (((GridLayoutManager.LayoutParams)
+                            child.getLayoutParams()).getSpanIndex() != 0) {
+                        continue;
+                    }
                     int height = child.getHeight();
                     offset += height;
 
-                    if (child.getTag() != null
-                            && (child.getTag() instanceof DirectShareViewHolder)) {
+                    if (mChooserGridAdapter.getTargetType(
+                            mRecyclerView.getChildAdapterPosition(child))
+                            == mChooserListAdapter.TARGET_SERVICE) {
                         directShareHeight = height;
                     }
+                    rowsToShow--;
                 }
 
                 boolean isExpandable = getResources().getConfiguration().orientation
@@ -2107,7 +2128,9 @@
 
     @Override // ChooserListCommunicator
     public int getMaxRankedTargets() {
-        return mChooserRowAdapter == null ? 4 : mChooserRowAdapter.getMaxTargetsPerRow();
+        return mChooserGridAdapter == null
+                ? ChooserGridAdapter.MAX_TARGETS_PER_ROW_PORTRAIT
+                : mChooserGridAdapter.getMaxTargetsPerRow();
     }
 
     @Override // ChooserListCommunicator
@@ -2175,7 +2198,40 @@
         return false;
     }
 
-    class ChooserRowAdapter extends BaseAdapter {
+    /**
+     * Used to bind types of individual item including
+     * {@link ChooserGridAdapter#VIEW_TYPE_NORMAL},
+     * {@link ChooserGridAdapter#VIEW_TYPE_CONTENT_PREVIEW},
+     * {@link ChooserGridAdapter#VIEW_TYPE_PROFILE},
+     * and {@link ChooserGridAdapter#VIEW_TYPE_AZ_LABEL}.
+     */
+    final class ItemViewHolder extends RecyclerView.ViewHolder {
+        ResolverListAdapter.ViewHolder mWrappedViewHolder;
+        int mListPosition = ChooserListAdapter.NO_POSITION;
+
+        ItemViewHolder(View itemView, boolean isClickable) {
+            super(itemView);
+            mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);
+            if (isClickable) {
+                itemView.setOnClickListener(v -> startSelected(mListPosition,
+                        false/* always */, true/* filterd */));
+                itemView.setOnLongClickListener(v -> {
+                    showTargetDetails(
+                            mChooserListAdapter.resolveInfoForPosition(
+                                    mListPosition, true/* filtered */));
+                    return true;
+                });
+            }
+        }
+    }
+
+    /**
+     * Adapter for all types of items and targets in ShareSheet.
+     * Note that ranked sections like Direct Share - while appearing grid-like - are handled on the
+     * row level by this adapter but not on the item level. Individual targets within the row are
+     * handled by {@link ChooserListAdapter}
+     */
+    final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
 
@@ -2191,13 +2247,15 @@
         private static final int VIEW_TYPE_CONTENT_PREVIEW = 2;
         private static final int VIEW_TYPE_PROFILE = 3;
         private static final int VIEW_TYPE_AZ_LABEL = 4;
+        private static final int VIEW_TYPE_CALLER_AND_RANK = 5;
 
         private static final int MAX_TARGETS_PER_ROW_PORTRAIT = 4;
         private static final int MAX_TARGETS_PER_ROW_LANDSCAPE = 8;
 
         private static final int NUM_EXPANSIONS_TO_HIDE_AZ_LABEL = 20;
 
-        public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
+        ChooserGridAdapter(ChooserListAdapter wrappedAdapter) {
+            super();
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
 
@@ -2213,7 +2271,7 @@
                 @Override
                 public void onInvalidated() {
                     super.onInvalidated();
-                    notifyDataSetInvalidated();
+                    notifyDataSetChanged();
                 }
             });
         }
@@ -2229,7 +2287,7 @@
                 return false;
             }
 
-            int newWidth =  width / getMaxTargetsPerRow();
+            int newWidth = width / getMaxTargetsPerRow();
             if (newWidth != mChooserTargetWidth) {
                 mChooserTargetWidth = newWidth;
                 return true;
@@ -2259,22 +2317,7 @@
             return oldValue;
         }
 
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        @Override
-        public boolean isEnabled(int position) {
-            int viewType = getItemViewType(position);
-            if (viewType == VIEW_TYPE_CONTENT_PREVIEW || viewType == VIEW_TYPE_AZ_LABEL) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public int getCount() {
+        public int getRowCount() {
             return (int) (
                     getContentPreviewRowCount()
                             + getProfileRowCount()
@@ -2326,42 +2369,50 @@
         }
 
         @Override
-        public Object getItem(int position) {
-            // We have nothing useful to return here.
-            return position;
+        public int getItemCount() {
+            return (int) (
+                    getContentPreviewRowCount()
+                            + getProfileRowCount()
+                            + getServiceTargetRowCount()
+                            + getCallerAndRankedTargetRowCount()
+                            + getAzLabelRowCount()
+                            + mChooserListAdapter.getAlphaTargetCount()
+            );
         }
 
         @Override
-        public long getItemId(int position) {
-            return position;
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            switch (viewType) {
+                case VIEW_TYPE_CONTENT_PREVIEW:
+                    return new ItemViewHolder(createContentPreviewView(parent), false);
+                case VIEW_TYPE_PROFILE:
+                    return new ItemViewHolder(createProfileView(parent), false);
+                case VIEW_TYPE_AZ_LABEL:
+                    return new ItemViewHolder(createAzLabelView(parent), false);
+                case VIEW_TYPE_NORMAL:
+                    return new ItemViewHolder(mChooserListAdapter.createView(parent), true);
+                case VIEW_TYPE_DIRECT_SHARE:
+                case VIEW_TYPE_CALLER_AND_RANK:
+                    return createItemGroupViewHolder(viewType, parent);
+                default:
+                    // Since we catch all possible viewTypes above, no chance this is being called.
+                    return null;
+            }
         }
 
         @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            final RowViewHolder holder;
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
             int viewType = getItemViewType(position);
-
-            if (viewType == VIEW_TYPE_CONTENT_PREVIEW) {
-                return createContentPreviewView(convertView, parent);
+            switch (viewType) {
+                case VIEW_TYPE_DIRECT_SHARE:
+                case VIEW_TYPE_CALLER_AND_RANK:
+                    bindItemGroupViewHolder(position, (ItemGroupViewHolder) holder);
+                    break;
+                case VIEW_TYPE_NORMAL:
+                    bindItemViewHolder(position, (ItemViewHolder) holder);
+                    break;
+                default:
             }
-
-            if (viewType == VIEW_TYPE_PROFILE) {
-                return createProfileView(convertView, parent);
-            }
-
-            if (viewType == VIEW_TYPE_AZ_LABEL) {
-                return createAzLabelView(parent);
-            }
-
-            if (convertView == null) {
-                holder = createViewHolder(viewType, parent);
-            } else {
-                holder = (RowViewHolder) convertView.getTag();
-            }
-
-            bindViewHolder(position, holder);
-
-            return holder.getViewGroup();
         }
 
         @Override
@@ -2378,7 +2429,7 @@
             if (count > 0 && position < countSum) return VIEW_TYPE_DIRECT_SHARE;
 
             countSum += (count = getCallerAndRankedTargetRowCount());
-            if (count > 0 && position < countSum) return VIEW_TYPE_NORMAL;
+            if (count > 0 && position < countSum) return VIEW_TYPE_CALLER_AND_RANK;
 
             countSum += (count = getAzLabelRowCount());
             if (count > 0 && position < countSum) return VIEW_TYPE_AZ_LABEL;
@@ -2386,27 +2437,22 @@
             return VIEW_TYPE_NORMAL;
         }
 
-        @Override
-        public int getViewTypeCount() {
-            return 5;
+        public int getTargetType(int position) {
+            return mChooserListAdapter.getPositionTargetType(getListPosition(position));
         }
 
-        private ViewGroup createContentPreviewView(View convertView, ViewGroup parent) {
+        private ViewGroup createContentPreviewView(ViewGroup parent) {
             Intent targetIntent = getTargetIntent();
             int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
 
-            if (convertView == null) {
-                getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+            getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
                         .setSubtype(previewType));
-            }
 
-            return displayContentPreview(previewType, targetIntent, mLayoutInflater,
-                    (ViewGroup) convertView, parent);
+            return displayContentPreview(previewType, targetIntent, mLayoutInflater, parent);
         }
 
-        private View createProfileView(View convertView, ViewGroup parent) {
-            View profileRow = convertView != null ? convertView : mLayoutInflater.inflate(
-                    R.layout.chooser_profile_row, parent, false);
+        private View createProfileView(ViewGroup parent) {
+            View profileRow = mLayoutInflater.inflate(R.layout.chooser_profile_row, parent, false);
             profileRow.setBackground(
                     getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
             mProfileView = profileRow.findViewById(R.id.profile_button);
@@ -2419,7 +2465,7 @@
             return mLayoutInflater.inflate(R.layout.chooser_az_label_row, parent, false);
         }
 
-        private RowViewHolder loadViewsIntoRow(RowViewHolder holder) {
+        private ItemGroupViewHolder loadViewsIntoGroup(ItemGroupViewHolder holder) {
             final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
             final int exactSpec = MeasureSpec.makeMeasureSpec(mChooserTargetWidth,
                     MeasureSpec.EXACTLY);
@@ -2445,7 +2491,7 @@
                         return true;
                     }
                 });
-                ViewGroup row = holder.addView(i, v);
+                holder.addView(i, v);
 
                 // Force Direct Share to be 2 lines and auto-wrap to second line via hoz scroll =
                 // false. TextView#setHorizontallyScrolling must be reset after #setLines. Must be
@@ -2490,7 +2536,7 @@
             }
         }
 
-        RowViewHolder createViewHolder(int viewType, ViewGroup parent) {
+        ItemGroupViewHolder createItemGroupViewHolder(int viewType, ViewGroup parent) {
             if (viewType == VIEW_TYPE_DIRECT_SHARE) {
                 ViewGroup parentGroup = (ViewGroup) mLayoutInflater.inflate(
                         R.layout.chooser_row_direct_share, parent, false);
@@ -2503,14 +2549,14 @@
 
                 mDirectShareViewHolder = new DirectShareViewHolder(parentGroup,
                         Lists.newArrayList(row1, row2), getMaxTargetsPerRow());
-                loadViewsIntoRow(mDirectShareViewHolder);
+                loadViewsIntoGroup(mDirectShareViewHolder);
 
                 return mDirectShareViewHolder;
             } else {
                 ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row, parent,
                         false);
-                RowViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
-                loadViewsIntoRow(holder);
+                ItemGroupViewHolder holder = new SingleRowViewHolder(row, getMaxTargetsPerRow());
+                loadViewsIntoGroup(holder);
 
                 return holder;
             }
@@ -2538,19 +2584,20 @@
             return positionType;
         }
 
-        void bindViewHolder(int rowPosition, RowViewHolder holder) {
-            final int start = getFirstRowPosition(rowPosition);
-            final int startType = getRowType(start);
-            final int lastStartType = getRowType(getFirstRowPosition(rowPosition - 1));
+        void bindItemViewHolder(int position, ItemViewHolder holder) {
+            View v = holder.itemView;
+            int listPosition = getListPosition(position);
+            holder.mListPosition = listPosition;
+            mChooserListAdapter.bindView(listPosition, v);
+        }
 
-            final ViewGroup row = holder.getViewGroup();
-
-            if (startType != lastStartType
-                    || rowPosition == getContentPreviewRowCount() + getProfileRowCount()) {
-                row.setForeground(
+        void bindItemGroupViewHolder(int position, ItemGroupViewHolder holder) {
+            final ViewGroup viewGroup = (ViewGroup) holder.itemView;
+            int start = getListPosition(position);
+            int startType = getRowType(start);
+            if (viewGroup.getForeground() == null) {
+                viewGroup.setForeground(
                         getResources().getDrawable(R.drawable.chooser_row_layer_list, null));
-            } else {
-                row.setForeground(null);
             }
 
             int columnCount = holder.getColumnCount();
@@ -2560,7 +2607,7 @@
             }
 
             if (end == start && mChooserListAdapter.getItem(start) instanceof EmptyTargetInfo) {
-                final TextView textView = row.findViewById(R.id.chooser_row_text_option);
+                final TextView textView = viewGroup.findViewById(R.id.chooser_row_text_option);
 
                 if (textView.getVisibility() != View.VISIBLE) {
                     textView.setAlpha(0.0f);
@@ -2597,27 +2644,28 @@
             }
         }
 
-        int getFirstRowPosition(int row) {
-            row -= getContentPreviewRowCount() + getProfileRowCount();
+        int getListPosition(int position) {
+            position -= getContentPreviewRowCount() + getProfileRowCount();
 
             final int serviceCount = mChooserListAdapter.getServiceTargetCount();
             final int serviceRows = (int) Math.ceil((float) serviceCount
                     / ChooserListAdapter.MAX_SERVICE_TARGETS);
-            if (row < serviceRows) {
-                return row * getMaxTargetsPerRow();
+            if (position < serviceRows) {
+                return position * getMaxTargetsPerRow();
             }
 
+            position -= serviceRows;
+
             final int callerAndRankedCount = mChooserListAdapter.getCallerTargetCount()
                                                  + mChooserListAdapter.getRankedTargetCount();
             final int callerAndRankedRows = getCallerAndRankedTargetRowCount();
-            if (row < callerAndRankedRows + serviceRows) {
-                return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
+            if (position < callerAndRankedRows) {
+                return serviceCount + position * getMaxTargetsPerRow();
             }
 
-            row -= getAzLabelRowCount();
+            position -= getAzLabelRowCount() + callerAndRankedRows;
 
-            return callerAndRankedCount + serviceCount
-                    + (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow();
+            return callerAndRankedCount + serviceCount + position;
         }
 
         public void handleScroll(View v, int y, int oldy) {
@@ -2631,18 +2679,24 @@
                     && !isInMultiWindowMode();
 
             if (mDirectShareViewHolder != null && canExpandDirectShare) {
-                mDirectShareViewHolder.handleScroll(mAdapterView, y, oldy, getMaxTargetsPerRow());
+                mDirectShareViewHolder.handleScroll(mRecyclerView, y, oldy, getMaxTargetsPerRow());
             }
         }
     }
 
-    abstract class RowViewHolder {
+    /**
+     * Used to bind types for group of items including:
+     * {@link ChooserGridAdapter#VIEW_TYPE_DIRECT_SHARE},
+     * and {@link ChooserGridAdapter#VIEW_TYPE_CALLER_AND_RANK}.
+     */
+    abstract class ItemGroupViewHolder extends RecyclerView.ViewHolder {
         protected int mMeasuredRowHeight;
         private int[] mItemIndices;
         protected final View[] mCells;
         private final int mColumnCount;
 
-        RowViewHolder(int cellCount) {
+        ItemGroupViewHolder(int cellCount, View itemView) {
+            super(itemView);
             this.mCells = new View[cellCount];
             this.mItemIndices = new int[cellCount];
             this.mColumnCount = cellCount;
@@ -2685,11 +2739,11 @@
         }
     }
 
-    class SingleRowViewHolder extends RowViewHolder {
+    class SingleRowViewHolder extends ItemGroupViewHolder {
         private final ViewGroup mRow;
 
         SingleRowViewHolder(ViewGroup row, int cellCount) {
-            super(cellCount);
+            super(cellCount, row);
 
             this.mRow = row;
         }
@@ -2719,7 +2773,7 @@
         }
     }
 
-    class DirectShareViewHolder extends RowViewHolder {
+    class DirectShareViewHolder extends ItemGroupViewHolder {
         private final ViewGroup mParent;
         private final List<ViewGroup> mRows;
         private int mCellCountPerRow;
@@ -2732,7 +2786,7 @@
         private final boolean[] mCellVisibility;
 
         DirectShareViewHolder(ViewGroup parent, List<ViewGroup> rows, int cellCountPerRow) {
-            super(rows.size() * cellCountPerRow);
+            super(rows.size() * cellCountPerRow, parent);
 
             this.mParent = parent;
             this.mRows = rows;
@@ -2767,7 +2821,7 @@
 
             mDirectShareMinHeight = getRow(0).getMeasuredHeight();
             mDirectShareCurrHeight = mDirectShareCurrHeight > 0
-                                         ? mDirectShareCurrHeight : mDirectShareMinHeight;
+                    ? mDirectShareCurrHeight : mDirectShareMinHeight;
             mDirectShareMaxHeight = 2 * mDirectShareMinHeight;
         }
 
@@ -2800,7 +2854,7 @@
             }
         }
 
-        public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
+        public void handleScroll(RecyclerView view, int y, int oldy, int maxTargetsPerRow) {
             // only exit early if fully collapsed, otherwise onListRebuilt() with shifting
             // targets can lock us into an expanded mode
             boolean notExpanded = mDirectShareCurrHeight == mDirectShareMinHeight;
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 38f4c64..4eccf21 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -49,6 +49,7 @@
     private static final String TAG = "ChooserListAdapter";
     private static final boolean DEBUG = false;
 
+    public static final int NO_POSITION = -1;
     public static final int TARGET_BAD = -1;
     public static final int TARGET_CALLER = 0;
     public static final int TARGET_SERVICE = 1;
@@ -189,7 +190,7 @@
     }
 
     @Override
-    public View onCreateView(ViewGroup parent) {
+    View onCreateView(ViewGroup parent) {
         return mInflater.inflate(
                 com.android.internal.R.layout.resolve_grid_item, parent, false);
     }
@@ -321,6 +322,10 @@
      */
     @Override
     public TargetInfo targetInfoForPosition(int position, boolean filtered) {
+        if (position == NO_POSITION) {
+            return null;
+        }
+
         int offset = 0;
 
         // Direct share targets
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 1beb1c5..0997cf8 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -97,7 +97,7 @@
     @UnsupportedAppUsage
     protected ResolverListAdapter mAdapter;
     private boolean mSafeForwardingMode;
-    protected AbsListView mAdapterView;
+    private AbsListView mAdapterView;
     private Button mAlwaysButton;
     private Button mOnceButton;
     protected View mProfileView;
@@ -328,9 +328,8 @@
         boolean filterLastUsed = mSupportsAlwaysUseOption && !isVoiceInteraction();
         mAdapter = createAdapter(this, mIntents, initialIntents, rList,
                 filterLastUsed, mUseLayoutForBrowsables);
-        configureContentView();
 
-        if (rebuildList()) {
+        if (configureContentView()) {
             return;
         }
 
@@ -1063,33 +1062,39 @@
 
     /**
      * Sets up the content view.
+     * @return <code>true</code> if the activity is finishing and creation should halt.
      */
-    private void configureContentView() {
+    private boolean configureContentView() {
         if (mAdapter == null) {
             throw new IllegalStateException("mAdapter cannot be null.");
         }
+        boolean rebuildCompleted = mAdapter.rebuildList();
         if (useLayoutWithDefault()) {
             mLayoutId = R.layout.resolver_list_with_default;
         } else {
             mLayoutId = getLayoutResource();
         }
         setContentView(mLayoutId);
-        mAdapterView = findViewById(R.id.resolver_list);
+        return postRebuildList(rebuildCompleted);
     }
 
     /**
-     * Returns true if the activity is finishing and creation should halt.
-     * </p>Subclasses must call rebuildListInternal at the end of rebuildList.
+     * Finishing procedures to be performed after the list has been rebuilt.
+     * </p>Subclasses must call postRebuildListInternal at the end of postRebuildList.
+     * @param rebuildCompleted
+     * @return <code>true</code> if the activity is finishing and creation should halt.
      */
-    protected boolean rebuildList() {
-        return rebuildListInternal();
+    protected boolean postRebuildList(boolean rebuildCompleted) {
+        return postRebuildListInternal(rebuildCompleted);
     }
 
     /**
-     * Returns true if the activity is finishing and creation should halt.
+     * Finishing procedures to be performed after the list has been rebuilt.
+     * @param rebuildCompleted
+     * @return <code>true</code> if the activity is finishing and creation should halt.
      */
-    final boolean rebuildListInternal() {
-        boolean rebuildCompleted = mAdapter.rebuildList();
+    final boolean postRebuildListInternal(boolean rebuildCompleted) {
+
         int count = mAdapter.getUnfilteredCount();
 
         // We only rebuild asynchronously when we have multiple elements to sort. In the case where
@@ -1108,26 +1113,37 @@
             }
         }
 
+        boolean isAdapterViewVisible = true;
         if (count == 0 && mAdapter.getPlaceholderCount() == 0) {
             final TextView emptyView = findViewById(R.id.empty);
             emptyView.setVisibility(View.VISIBLE);
-            mAdapterView.setVisibility(View.GONE);
-        } else {
-            mAdapterView.setVisibility(View.VISIBLE);
-            onPrepareAdapterView(mAdapterView, mAdapter);
+            isAdapterViewVisible = false;
         }
+
+        onPrepareAdapterView(mAdapter, isAdapterViewVisible);
         return false;
     }
 
-    public void onPrepareAdapterView(AbsListView adapterView, ResolverListAdapter adapter) {
+    /**
+     * Prepare the scrollable view which consumes data in the list adapter.
+     * @param adapter The adapter used to provide data to item views.
+     * @param isVisible True if the scrollable view should be visible; false, otherwise.
+     */
+    public void onPrepareAdapterView(ResolverListAdapter adapter, boolean isVisible) {
+        mAdapterView = findViewById(R.id.resolver_list);
+        if (!isVisible) {
+            mAdapterView.setVisibility(View.GONE);
+            return;
+        }
+        mAdapterView.setVisibility(View.VISIBLE);
         final boolean useHeader = adapter.hasFilteredItem();
-        final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
+        final ListView listView = mAdapterView instanceof ListView ? (ListView) mAdapterView : null;
 
-        adapterView.setAdapter(mAdapter);
+        mAdapterView.setAdapter(mAdapter);
 
         final ItemClickListener listener = new ItemClickListener();
-        adapterView.setOnItemClickListener(listener);
-        adapterView.setOnItemLongClickListener(listener);
+        mAdapterView.setOnItemClickListener(listener);
+        mAdapterView.setOnItemLongClickListener(listener);
 
         if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
             listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 0286aa6..4570c6f 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -491,7 +491,7 @@
         return view;
     }
 
-    public View onCreateView(ViewGroup parent) {
+    View onCreateView(ViewGroup parent) {
         return mInflater.inflate(
                 com.android.internal.R.layout.resolve_list_item, parent, false);
     }
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 21bb664..227ef28 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -24,7 +24,6 @@
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
-import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
@@ -112,7 +111,6 @@
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.MenuView;
 import com.android.internal.widget.DecorContentParent;
-import com.android.internal.widget.SwipeDismissLayout;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -378,15 +376,6 @@
             removeFeature(FEATURE_ACTION_BAR);
         }
 
-        if ((features & (1 << FEATURE_ACTION_BAR)) != 0 && featureId == FEATURE_SWIPE_TO_DISMISS) {
-            throw new AndroidRuntimeException(
-                    "You cannot combine swipe dismissal and the action bar.");
-        }
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0 && featureId == FEATURE_ACTION_BAR) {
-            throw new AndroidRuntimeException(
-                    "You cannot combine swipe dismissal and the action bar.");
-        }
-
         if (featureId == FEATURE_INDETERMINATE_PROGRESS &&
                 getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
             throw new AndroidRuntimeException("You cannot use indeterminate progress on a watch.");
@@ -2373,10 +2362,6 @@
             requestFeature(FEATURE_ACTION_MODE_OVERLAY);
         }
 
-        if (a.getBoolean(R.styleable.Window_windowSwipeToDismiss, false)) {
-            requestFeature(FEATURE_SWIPE_TO_DISMISS);
-        }
-
         if (a.getBoolean(R.styleable.Window_windowFullscreen, false)) {
             setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN & (~getForcedWindowFlags()));
         }
@@ -2393,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()));
         }
@@ -2565,10 +2546,7 @@
         int layoutResource;
         int features = getLocalFeatures();
         // System.out.println("Features: 0x" + Integer.toHexString(features));
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            layoutResource = R.layout.screen_swipe_dismiss;
-            setCloseOnSwipeEnabled(true);
-        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
+        if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
             if (mIsFloating) {
                 TypedValue res = new TypedValue();
                 getContext().getTheme().resolveAttribute(
@@ -2638,10 +2616,6 @@
             }
         }
 
-        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {
-            registerSwipeCallbacks(contentParent);
-        }
-
         // Remaining setup -- of background and title -- that only applies
         // to top-level windows.
         if (getContainer() == null) {
@@ -3047,63 +3021,6 @@
         return (mRightIconView = (ImageView)findViewById(R.id.right_icon));
     }
 
-    private void registerSwipeCallbacks(ViewGroup contentParent) {
-        if (!(contentParent instanceof SwipeDismissLayout)) {
-            Log.w(TAG, "contentParent is not a SwipeDismissLayout: " + contentParent);
-            return;
-        }
-        SwipeDismissLayout swipeDismiss = (SwipeDismissLayout) contentParent;
-        swipeDismiss.setOnDismissedListener(new SwipeDismissLayout.OnDismissedListener() {
-            @Override
-            public void onDismissed(SwipeDismissLayout layout) {
-                dispatchOnWindowSwipeDismissed();
-                dispatchOnWindowDismissed(false /*finishTask*/, true /*suppressWindowTransition*/);
-            }
-        });
-        swipeDismiss.setOnSwipeProgressChangedListener(
-                new SwipeDismissLayout.OnSwipeProgressChangedListener() {
-                    @Override
-                    public void onSwipeProgressChanged(
-                            SwipeDismissLayout layout, float alpha, float translate) {
-                        WindowManager.LayoutParams newParams = getAttributes();
-                        newParams.x = (int) translate;
-                        newParams.alpha = alpha;
-                        setAttributes(newParams);
-
-                        int flags = 0;
-                        if (newParams.x == 0) {
-                            flags = FLAG_FULLSCREEN;
-                        } else {
-                            flags = FLAG_LAYOUT_NO_LIMITS;
-                        }
-                        setFlags(flags, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
-                    }
-
-                    @Override
-                    public void onSwipeCancelled(SwipeDismissLayout layout) {
-                        WindowManager.LayoutParams newParams = getAttributes();
-                        // Swipe changes only affect the x-translation and alpha, check to see if
-                        // those values have changed first before resetting them.
-                        if (newParams.x != 0 || newParams.alpha != 1) {
-                            newParams.x = 0;
-                            newParams.alpha = 1;
-                            setAttributes(newParams);
-                            setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN | FLAG_LAYOUT_NO_LIMITS);
-                        }
-                    }
-                });
-    }
-
-    /** @hide */
-    @Override
-    public void setCloseOnSwipeEnabled(boolean closeOnSwipeEnabled) {
-        if (hasFeature(Window.FEATURE_SWIPE_TO_DISMISS) // swipe-to-dismiss feature is requested
-                && mContentParent instanceof SwipeDismissLayout) { // check casting mContentParent
-            ((SwipeDismissLayout) mContentParent).setDismissable(closeOnSwipeEnabled);
-        }
-        super.setCloseOnSwipeEnabled(closeOnSwipeEnabled);
-    }
-
     /**
      * Helper method for calling the {@link Callback#onPanelClosed(int, Menu)}
      * callback. This method will grab whatever extra state is needed for the
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/java/com/android/internal/widget/GridLayoutManager.java b/core/java/com/android/internal/widget/GridLayoutManager.java
new file mode 100644
index 0000000..e0502f1
--- /dev/null
+++ b/core/java/com/android/internal/widget/GridLayoutManager.java
@@ -0,0 +1,1065 @@
+/*
+ * 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.internal.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import java.util.Arrays;
+
+/**
+ * Note: This GridLayoutManager widget may lack of latest fix because it is ported from
+ * oc-dr1-release version of android.support.v7.widget.GridLayoutManager due to compatibility
+ * concern with other internal widgets, like {@link RecyclerView} and {@link LinearLayoutManager},
+ * and is merely used for {@link com.android.internal.app.ChooserActivity}.
+ *
+ * A {@link RecyclerView.LayoutManager} implementations that lays out items in a grid.
+ * <p>
+ * By default, each item occupies 1 span. You can change it by providing a custom
+ * {@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}.
+ */
+public class GridLayoutManager extends LinearLayoutManager {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "GridLayoutManager";
+    public static final int DEFAULT_SPAN_COUNT = -1;
+    /**
+     * Span size have been changed but we've not done a new layout calculation.
+     */
+    boolean mPendingSpanCountChange = false;
+    int mSpanCount = DEFAULT_SPAN_COUNT;
+    /**
+     * Right borders for each span.
+     * <p>For <b>i-th</b> item start is {@link #mCachedBorders}[i-1] + 1
+     * and end is {@link #mCachedBorders}[i].
+     */
+    int[] mCachedBorders;
+    /**
+     * Temporary array to keep views in layoutChunk method
+     */
+    View[] mSet;
+    final SparseIntArray mPreLayoutSpanSizeCache = new SparseIntArray();
+    final SparseIntArray mPreLayoutSpanIndexCache = new SparseIntArray();
+    SpanSizeLookup mSpanSizeLookup = new DefaultSpanSizeLookup();
+    // re-used variable to acquire decor insets from RecyclerView
+    final Rect mDecorInsets = new Rect();
+
+    /**
+     * Constructor used when layout manager is set in XML by RecyclerView attribute
+     * "layoutManager". If spanCount is not specified in the XML, it defaults to a
+     * single column.
+     *
+     */
+    public GridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes);
+        setSpanCount(properties.spanCount);
+    }
+
+    /**
+     * Creates a vertical GridLayoutManager
+     *
+     * @param context   Current context, will be used to access resources.
+     * @param spanCount The number of columns in the grid
+     */
+    public GridLayoutManager(Context context, int spanCount) {
+        super(context);
+        setSpanCount(spanCount);
+    }
+
+    /**
+     * @param context       Current context, will be used to access resources.
+     * @param spanCount     The number of columns or rows in the grid
+     * @param orientation   Layout orientation. Should be {@link #HORIZONTAL} or {@link
+     *                      #VERTICAL}.
+     * @param reverseLayout When set to true, layouts from end to start.
+     */
+    public GridLayoutManager(Context context, int spanCount, int orientation,
+            boolean reverseLayout) {
+        super(context, orientation, reverseLayout);
+        setSpanCount(spanCount);
+    }
+
+    /**
+     * stackFromEnd is not supported by GridLayoutManager. Consider using
+     * {@link #setReverseLayout(boolean)}.
+     */
+    @Override
+    public void setStackFromEnd(boolean stackFromEnd) {
+        if (stackFromEnd) {
+            throw new UnsupportedOperationException(
+                    "GridLayoutManager does not support stack from end."
+                            + " Consider using reverse layout");
+        }
+        super.setStackFromEnd(false);
+    }
+
+    @Override
+    public int getRowCountForAccessibility(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == HORIZONTAL) {
+            return mSpanCount;
+        }
+        if (state.getItemCount() < 1) {
+            return 0;
+        }
+        // Row count is one more than the last item's row index.
+        return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1;
+    }
+
+    @Override
+    public int getColumnCountForAccessibility(RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        if (mOrientation == VERTICAL) {
+            return mSpanCount;
+        }
+        if (state.getItemCount() < 1) {
+            return 0;
+        }
+        // Column count is one more than the last item's column index.
+        return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+            RecyclerView.State state, View host, AccessibilityNodeInfo info) {
+        ViewGroup.LayoutParams lp = host.getLayoutParams();
+        if (!(lp instanceof LayoutParams)) {
+            super.onInitializeAccessibilityNodeInfoForItem(host, info);
+            return;
+        }
+        LayoutParams glp = (LayoutParams) lp;
+        int spanGroupIndex = getSpanGroupIndex(recycler, state, glp.getViewLayoutPosition());
+        if (mOrientation == HORIZONTAL) {
+            info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
+                    glp.getSpanIndex(), glp.getSpanSize(),
+                    spanGroupIndex, 1,
+                    mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+        } else { // VERTICAL
+            info.setCollectionItemInfo(AccessibilityNodeInfo.CollectionItemInfo.obtain(
+                    spanGroupIndex, 1,
+                    glp.getSpanIndex(), glp.getSpanSize(),
+                    mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false));
+        }
+    }
+
+    @Override
+    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
+        if (state.isPreLayout()) {
+            cachePreLayoutSpanMapping();
+        }
+        super.onLayoutChildren(recycler, state);
+        if (DEBUG) {
+            validateChildOrder();
+        }
+        clearPreLayoutSpanMappingCache();
+    }
+
+    @Override
+    public void onLayoutCompleted(RecyclerView.State state) {
+        super.onLayoutCompleted(state);
+        mPendingSpanCountChange = false;
+    }
+
+    private void clearPreLayoutSpanMappingCache() {
+        mPreLayoutSpanSizeCache.clear();
+        mPreLayoutSpanIndexCache.clear();
+    }
+
+    private void cachePreLayoutSpanMapping() {
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+            final int viewPosition = lp.getViewLayoutPosition();
+            mPreLayoutSpanSizeCache.put(viewPosition, lp.getSpanSize());
+            mPreLayoutSpanIndexCache.put(viewPosition, lp.getSpanIndex());
+        }
+    }
+
+    @Override
+    public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) {
+        mSpanSizeLookup.invalidateSpanIndexCache();
+    }
+
+    @Override
+    public void onItemsChanged(RecyclerView recyclerView) {
+        mSpanSizeLookup.invalidateSpanIndexCache();
+    }
+
+    @Override
+    public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) {
+        mSpanSizeLookup.invalidateSpanIndexCache();
+    }
+
+    @Override
+    public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount,
+            Object payload) {
+        mSpanSizeLookup.invalidateSpanIndexCache();
+    }
+
+    @Override
+    public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) {
+        mSpanSizeLookup.invalidateSpanIndexCache();
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateDefaultLayoutParams() {
+        if (mOrientation == HORIZONTAL) {
+            return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT);
+        } else {
+            return new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT);
+        }
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) {
+        return new LayoutParams(c, attrs);
+    }
+
+    @Override
+    public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp instanceof ViewGroup.MarginLayoutParams) {
+            return new LayoutParams((ViewGroup.MarginLayoutParams) lp);
+        } else {
+            return new LayoutParams(lp);
+        }
+    }
+
+    @Override
+    public boolean checkLayoutParams(RecyclerView.LayoutParams lp) {
+        return lp instanceof LayoutParams;
+    }
+
+    /**
+     * Sets the source to get the number of spans occupied by each item in the adapter.
+     *
+     * @param spanSizeLookup {@link SpanSizeLookup} instance to be used to query number of spans
+     *                       occupied by each item
+     */
+    public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
+        mSpanSizeLookup = spanSizeLookup;
+    }
+
+    /**
+     * Returns the current {@link SpanSizeLookup} used by the GridLayoutManager.
+     *
+     * @return The current {@link SpanSizeLookup} used by the GridLayoutManager.
+     */
+    public SpanSizeLookup getSpanSizeLookup() {
+        return mSpanSizeLookup;
+    }
+
+    private void updateMeasurements() {
+        int totalSpace;
+        if (getOrientation() == VERTICAL) {
+            totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();
+        } else {
+            totalSpace = getHeight() - getPaddingBottom() - getPaddingTop();
+        }
+        calculateItemBorders(totalSpace);
+    }
+
+    @Override
+    public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
+        if (mCachedBorders == null) {
+            super.setMeasuredDimension(childrenBounds, wSpec, hSpec);
+        }
+        final int width, height;
+        final int horizontalPadding = getPaddingLeft() + getPaddingRight();
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
+        if (mOrientation == VERTICAL) {
+            final int usedHeight = childrenBounds.height() + verticalPadding;
+            height = chooseSize(hSpec, usedHeight, getMinimumHeight());
+            width = chooseSize(wSpec, mCachedBorders[mCachedBorders.length - 1] + horizontalPadding,
+                    getMinimumWidth());
+        } else {
+            final int usedWidth = childrenBounds.width() + horizontalPadding;
+            width = chooseSize(wSpec, usedWidth, getMinimumWidth());
+            height = chooseSize(hSpec, mCachedBorders[mCachedBorders.length - 1] + verticalPadding,
+                    getMinimumHeight());
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    /**
+     * @param totalSpace Total available space after padding is removed
+     */
+    private void calculateItemBorders(int totalSpace) {
+        mCachedBorders = calculateItemBorders(mCachedBorders, mSpanCount, totalSpace);
+    }
+
+    /**
+     * @param cachedBorders The out array
+     * @param spanCount     number of spans
+     * @param totalSpace    total available space after padding is removed
+     * @return The updated array. Might be the same instance as the provided array if its size
+     * has not changed.
+     */
+    static int[] calculateItemBorders(int[] cachedBorders, int spanCount, int totalSpace) {
+        if (cachedBorders == null || cachedBorders.length != spanCount + 1
+                || cachedBorders[cachedBorders.length - 1] != totalSpace) {
+            cachedBorders = new int[spanCount + 1];
+        }
+        cachedBorders[0] = 0;
+        int sizePerSpan = totalSpace / spanCount;
+        int sizePerSpanRemainder = totalSpace % spanCount;
+        int consumedPixels = 0;
+        int additionalSize = 0;
+        for (int i = 1; i <= spanCount; i++) {
+            int itemSize = sizePerSpan;
+            additionalSize += sizePerSpanRemainder;
+            if (additionalSize > 0 && (spanCount - additionalSize) < sizePerSpanRemainder) {
+                itemSize += 1;
+                additionalSize -= spanCount;
+            }
+            consumedPixels += itemSize;
+            cachedBorders[i] = consumedPixels;
+        }
+        return cachedBorders;
+    }
+
+    int getSpaceForSpanRange(int startSpan, int spanSize) {
+        if (mOrientation == VERTICAL && isLayoutRTL()) {
+            return mCachedBorders[mSpanCount - startSpan]
+                    - mCachedBorders[mSpanCount - startSpan - spanSize];
+        } else {
+            return mCachedBorders[startSpan + spanSize] - mCachedBorders[startSpan];
+        }
+    }
+
+    @Override
+    void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state,
+            AnchorInfo anchorInfo, int itemDirection) {
+        super.onAnchorReady(recycler, state, anchorInfo, itemDirection);
+        updateMeasurements();
+        if (state.getItemCount() > 0 && !state.isPreLayout()) {
+            ensureAnchorIsInCorrectSpan(recycler, state, anchorInfo, itemDirection);
+        }
+        ensureViewSet();
+    }
+
+    private void ensureViewSet() {
+        if (mSet == null || mSet.length != mSpanCount) {
+            mSet = new View[mSpanCount];
+        }
+    }
+
+    @Override
+    public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        updateMeasurements();
+        ensureViewSet();
+        return super.scrollHorizontallyBy(dx, recycler, state);
+    }
+
+    @Override
+    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
+            RecyclerView.State state) {
+        updateMeasurements();
+        ensureViewSet();
+        return super.scrollVerticallyBy(dy, recycler, state);
+    }
+
+    private void ensureAnchorIsInCorrectSpan(RecyclerView.Recycler recycler,
+            RecyclerView.State state, AnchorInfo anchorInfo, int itemDirection) {
+        final boolean layingOutInPrimaryDirection =
+                itemDirection == LayoutState.ITEM_DIRECTION_TAIL;
+        int span = getSpanIndex(recycler, state, anchorInfo.mPosition);
+        if (layingOutInPrimaryDirection) {
+            // choose span 0
+            while (span > 0 && anchorInfo.mPosition > 0) {
+                anchorInfo.mPosition--;
+                span = getSpanIndex(recycler, state, anchorInfo.mPosition);
+            }
+        } else {
+            // choose the max span we can get. hopefully last one
+            final int indexLimit = state.getItemCount() - 1;
+            int pos = anchorInfo.mPosition;
+            int bestSpan = span;
+            while (pos < indexLimit) {
+                int next = getSpanIndex(recycler, state, pos + 1);
+                if (next > bestSpan) {
+                    pos += 1;
+                    bestSpan = next;
+                } else {
+                    break;
+                }
+            }
+            anchorInfo.mPosition = pos;
+        }
+    }
+
+    @Override
+    View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state,
+            int start, int end, int itemCount) {
+        ensureLayoutState();
+        View invalidMatch = null;
+        View outOfBoundsMatch = null;
+        final int boundsStart = mOrientationHelper.getStartAfterPadding();
+        final int boundsEnd = mOrientationHelper.getEndAfterPadding();
+        final int diff = end > start ? 1 : -1;
+        for (int i = start; i != end; i += diff) {
+            final View view = getChildAt(i);
+            final int position = getPosition(view);
+            if (position >= 0 && position < itemCount) {
+                final int span = getSpanIndex(recycler, state, position);
+                if (span != 0) {
+                    continue;
+                }
+                if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) {
+                    if (invalidMatch == null) {
+                        invalidMatch = view; // removed item, least preferred
+                    }
+                } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd
+                        || mOrientationHelper.getDecoratedEnd(view) < boundsStart) {
+                    if (outOfBoundsMatch == null) {
+                        outOfBoundsMatch = view; // item is not visible, less preferred
+                    }
+                } else {
+                    return view;
+                }
+            }
+        }
+        return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch;
+    }
+
+    private int getSpanGroupIndex(RecyclerView.Recycler recycler, RecyclerView.State state,
+            int viewPosition) {
+        if (!state.isPreLayout()) {
+            return mSpanSizeLookup.getSpanGroupIndex(viewPosition, mSpanCount);
+        }
+        final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(viewPosition);
+        if (adapterPosition == -1) {
+            if (DEBUG) {
+                throw new RuntimeException("Cannot find span group index for position "
+                        + viewPosition);
+            }
+            Log.w(TAG, "Cannot find span size for pre layout position. " + viewPosition);
+            return 0;
+        }
+        return mSpanSizeLookup.getSpanGroupIndex(adapterPosition, mSpanCount);
+    }
+
+    private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) {
+        if (!state.isPreLayout()) {
+            return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount);
+        }
+        final int cached = mPreLayoutSpanIndexCache.get(pos, -1);
+        if (cached != -1) {
+            return cached;
+        }
+        final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos);
+        if (adapterPosition == -1) {
+            if (DEBUG) {
+                throw new RuntimeException("Cannot find span index for pre layout position. It is"
+                        + " not cached, not in the adapter. Pos:" + pos);
+            }
+            Log.w(TAG, "Cannot find span size for pre layout position. It is"
+                    + " not cached, not in the adapter. Pos:" + pos);
+            return 0;
+        }
+        return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, mSpanCount);
+    }
+
+    private int getSpanSize(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) {
+        if (!state.isPreLayout()) {
+            return mSpanSizeLookup.getSpanSize(pos);
+        }
+        final int cached = mPreLayoutSpanSizeCache.get(pos, -1);
+        if (cached != -1) {
+            return cached;
+        }
+        final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos);
+        if (adapterPosition == -1) {
+            if (DEBUG) {
+                throw new RuntimeException("Cannot find span size for pre layout position. It is"
+                        + " not cached, not in the adapter. Pos:" + pos);
+            }
+            Log.w(TAG, "Cannot find span size for pre layout position. It is"
+                    + " not cached, not in the adapter. Pos:" + pos);
+            return 1;
+        }
+        return mSpanSizeLookup.getSpanSize(adapterPosition);
+    }
+
+    @Override
+    void collectPrefetchPositionsForLayoutState(RecyclerView.State state, LayoutState layoutState,
+            LayoutPrefetchRegistry layoutPrefetchRegistry) {
+        int remainingSpan = mSpanCount;
+        int count = 0;
+        while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
+            final int pos = layoutState.mCurrentPosition;
+            layoutPrefetchRegistry.addPosition(pos, Math.max(0, layoutState.mScrollingOffset));
+            final int spanSize = mSpanSizeLookup.getSpanSize(pos);
+            remainingSpan -= spanSize;
+            layoutState.mCurrentPosition += layoutState.mItemDirection;
+            count++;
+        }
+    }
+
+    @Override
+    void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
+            LayoutState layoutState, LayoutChunkResult result) {
+        final int otherDirSpecMode = mOrientationHelper.getModeInOther();
+        final boolean flexibleInOtherDir = otherDirSpecMode != View.MeasureSpec.EXACTLY;
+        final int currentOtherDirSize = getChildCount() > 0 ? mCachedBorders[mSpanCount] : 0;
+        // if grid layout's dimensions are not specified, let the new row change the measurements
+        // This is not perfect since we not covering all rows but still solves an important case
+        // where they may have a header row which should be laid out according to children.
+        if (flexibleInOtherDir) {
+            updateMeasurements(); //  reset measurements
+        }
+        final boolean layingOutInPrimaryDirection =
+                layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL;
+        int count = 0;
+        int consumedSpanCount = 0;
+        int remainingSpan = mSpanCount;
+        if (!layingOutInPrimaryDirection) {
+            int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition);
+            int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition);
+            remainingSpan = itemSpanIndex + itemSpanSize;
+        }
+        while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) {
+            int pos = layoutState.mCurrentPosition;
+            final int spanSize = getSpanSize(recycler, state, pos);
+            if (spanSize > mSpanCount) {
+                throw new IllegalArgumentException("Item at position " + pos + " requires "
+                        + spanSize + " spans but GridLayoutManager has only " + mSpanCount
+                        + " spans.");
+            }
+            remainingSpan -= spanSize;
+            if (remainingSpan < 0) {
+                break; // item did not fit into this row or column
+            }
+            View view = layoutState.next(recycler);
+            if (view == null) {
+                break;
+            }
+            consumedSpanCount += spanSize;
+            mSet[count] = view;
+            count++;
+        }
+        if (count == 0) {
+            result.mFinished = true;
+            return;
+        }
+        int maxSize = 0;
+        float maxSizeInOther = 0; // use a float to get size per span
+        // we should assign spans before item decor offsets are calculated
+        assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection);
+        for (int i = 0; i < count; i++) {
+            View view = mSet[i];
+            if (layoutState.mScrapList == null) {
+                if (layingOutInPrimaryDirection) {
+                    addView(view);
+                } else {
+                    addView(view, 0);
+                }
+            } else {
+                if (layingOutInPrimaryDirection) {
+                    addDisappearingView(view);
+                } else {
+                    addDisappearingView(view, 0);
+                }
+            }
+            calculateItemDecorationsForChild(view, mDecorInsets);
+            measureChild(view, otherDirSpecMode, false);
+            final int size = mOrientationHelper.getDecoratedMeasurement(view);
+            if (size > maxSize) {
+                maxSize = size;
+            }
+            final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+            final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view)
+                    / lp.mSpanSize;
+            if (otherSize > maxSizeInOther) {
+                maxSizeInOther = otherSize;
+            }
+        }
+        if (flexibleInOtherDir) {
+            // re-distribute columns
+            guessMeasurement(maxSizeInOther, currentOtherDirSize);
+            // now we should re-measure any item that was match parent.
+            maxSize = 0;
+            for (int i = 0; i < count; i++) {
+                View view = mSet[i];
+                measureChild(view, View.MeasureSpec.EXACTLY, true);
+                final int size = mOrientationHelper.getDecoratedMeasurement(view);
+                if (size > maxSize) {
+                    maxSize = size;
+                }
+            }
+        }
+        // Views that did not measure the maxSize has to be re-measured
+        // We will stop doing this once we introduce Gravity in the GLM layout params
+        for (int i = 0; i < count; i++) {
+            final View view = mSet[i];
+            if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) {
+                final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+                final Rect decorInsets = lp.mDecorInsets;
+                final int verticalInsets = decorInsets.top + decorInsets.bottom
+                        + lp.topMargin + lp.bottomMargin;
+                final int horizontalInsets = decorInsets.left + decorInsets.right
+                        + lp.leftMargin + lp.rightMargin;
+                final int totalSpaceInOther = getSpaceForSpanRange(lp.mSpanIndex, lp.mSpanSize);
+                final int wSpec;
+                final int hSpec;
+                if (mOrientation == VERTICAL) {
+                    wSpec = getChildMeasureSpec(totalSpaceInOther, View.MeasureSpec.EXACTLY,
+                            horizontalInsets, lp.width, false);
+                    hSpec = View.MeasureSpec.makeMeasureSpec(maxSize - verticalInsets,
+                            View.MeasureSpec.EXACTLY);
+                } else {
+                    wSpec = View.MeasureSpec.makeMeasureSpec(maxSize - horizontalInsets,
+                            View.MeasureSpec.EXACTLY);
+                    hSpec = getChildMeasureSpec(totalSpaceInOther, View.MeasureSpec.EXACTLY,
+                            verticalInsets, lp.height, false);
+                }
+                measureChildWithDecorationsAndMargin(view, wSpec, hSpec, true);
+            }
+        }
+        result.mConsumed = maxSize;
+        int left = 0, right = 0, top = 0, bottom = 0;
+        if (mOrientation == VERTICAL) {
+            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
+                bottom = layoutState.mOffset;
+                top = bottom - maxSize;
+            } else {
+                top = layoutState.mOffset;
+                bottom = top + maxSize;
+            }
+        } else {
+            if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) {
+                right = layoutState.mOffset;
+                left = right - maxSize;
+            } else {
+                left = layoutState.mOffset;
+                right = left + maxSize;
+            }
+        }
+        for (int i = 0; i < count; i++) {
+            View view = mSet[i];
+            LayoutParams params = (LayoutParams) view.getLayoutParams();
+            if (mOrientation == VERTICAL) {
+                if (isLayoutRTL()) {
+                    right = getPaddingLeft() + mCachedBorders[mSpanCount - params.mSpanIndex];
+                    left = right - mOrientationHelper.getDecoratedMeasurementInOther(view);
+                } else {
+                    left = getPaddingLeft() + mCachedBorders[params.mSpanIndex];
+                    right = left + mOrientationHelper.getDecoratedMeasurementInOther(view);
+                }
+            } else {
+                top = getPaddingTop() + mCachedBorders[params.mSpanIndex];
+                bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view);
+            }
+            // We calculate everything with View's bounding box (which includes decor and margins)
+            // To calculate correct layout position, we subtract margins.
+            layoutDecoratedWithMargins(view, left, top, right, bottom);
+            if (DEBUG) {
+                Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:"
+                        + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:"
+                        + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin)
+                        + ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize);
+            }
+            // Consume the available space if the view is not removed OR changed
+            if (params.isItemRemoved() || params.isItemChanged()) {
+                result.mIgnoreConsumed = true;
+            }
+            result.mFocusable |= view.hasFocusable();
+        }
+        Arrays.fill(mSet, null);
+    }
+
+    /**
+     * Measures a child with currently known information. This is not necessarily the child's final
+     * measurement. (see fillChunk for details).
+     *
+     * @param view                   The child view to be measured
+     * @param otherDirParentSpecMode The RV measure spec that should be used in the secondary
+     *                               orientation
+     * @param alreadyMeasured        True if we've already measured this view once
+     */
+    private void measureChild(View view, int otherDirParentSpecMode, boolean alreadyMeasured) {
+        final LayoutParams lp = (LayoutParams) view.getLayoutParams();
+        final Rect decorInsets = lp.mDecorInsets;
+        final int verticalInsets = decorInsets.top + decorInsets.bottom
+                + lp.topMargin + lp.bottomMargin;
+        final int horizontalInsets = decorInsets.left + decorInsets.right
+                + lp.leftMargin + lp.rightMargin;
+        final int availableSpaceInOther = getSpaceForSpanRange(lp.mSpanIndex, lp.mSpanSize);
+        final int wSpec;
+        final int hSpec;
+        if (mOrientation == VERTICAL) {
+            wSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
+                    horizontalInsets, lp.width, false);
+            hSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), getHeightMode(),
+                    verticalInsets, lp.height, true);
+        } else {
+            hSpec = getChildMeasureSpec(availableSpaceInOther, otherDirParentSpecMode,
+                    verticalInsets, lp.height, false);
+            wSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), getWidthMode(),
+                    horizontalInsets, lp.width, true);
+        }
+        measureChildWithDecorationsAndMargin(view, wSpec, hSpec, alreadyMeasured);
+    }
+
+    /**
+     * This is called after laying out a row (if vertical) or a column (if horizontal) when the
+     * RecyclerView does not have exact measurement specs.
+     * <p>
+     * Here we try to assign a best guess width or height and re-do the layout to update other
+     * views that wanted to MATCH_PARENT in the non-scroll orientation.
+     *
+     * @param maxSizeInOther      The maximum size per span ratio from the measurement of the
+     *                            children.
+     * @param currentOtherDirSize The size before this layout chunk. There is no reason to go below.
+     */
+    private void guessMeasurement(float maxSizeInOther, int currentOtherDirSize) {
+        final int contentSize = Math.round(maxSizeInOther * mSpanCount);
+        // always re-calculate because borders were stretched during the fill
+        calculateItemBorders(Math.max(contentSize, currentOtherDirSize));
+    }
+
+    private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec,
+            boolean alreadyMeasured) {
+        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
+        final boolean measure;
+        if (alreadyMeasured) {
+            measure = shouldReMeasureChild(child, widthSpec, heightSpec, lp);
+        } else {
+            measure = shouldMeasureChild(child, widthSpec, heightSpec, lp);
+        }
+        if (measure) {
+            child.measure(widthSpec, heightSpec);
+        }
+    }
+
+    private void assignSpans(RecyclerView.Recycler recycler, RecyclerView.State state, int count,
+            int consumedSpanCount, boolean layingOutInPrimaryDirection) {
+        // spans are always assigned from 0 to N no matter if it is RTL or not.
+        // RTL is used only when positioning the view.
+        int span, start, end, diff;
+        // make sure we traverse from min position to max position
+        if (layingOutInPrimaryDirection) {
+            start = 0;
+            end = count;
+            diff = 1;
+        } else {
+            start = count - 1;
+            end = -1;
+            diff = -1;
+        }
+        span = 0;
+        for (int i = start; i != end; i += diff) {
+            View view = mSet[i];
+            LayoutParams params = (LayoutParams) view.getLayoutParams();
+            params.mSpanSize = getSpanSize(recycler, state, getPosition(view));
+            params.mSpanIndex = span;
+            span += params.mSpanSize;
+        }
+    }
+
+    /**
+     * Returns the number of spans laid out by this grid.
+     *
+     * @return The number of spans
+     * @see #setSpanCount(int)
+     */
+    public int getSpanCount() {
+        return mSpanCount;
+    }
+
+    /**
+     * Sets the number of spans to be laid out.
+     * <p>
+     * If {@link #getOrientation()} is {@link #VERTICAL}, this is the number of columns.
+     * If {@link #getOrientation()} is {@link #HORIZONTAL}, this is the number of rows.
+     *
+     * @param spanCount The total number of spans in the grid
+     * @see #getSpanCount()
+     */
+    public void setSpanCount(int spanCount) {
+        if (spanCount == mSpanCount) {
+            return;
+        }
+        mPendingSpanCountChange = true;
+        if (spanCount < 1) {
+            throw new IllegalArgumentException("Span count should be at least 1. Provided "
+                    + spanCount);
+        }
+        mSpanCount = spanCount;
+        mSpanSizeLookup.invalidateSpanIndexCache();
+        requestLayout();
+    }
+
+    /**
+     * A helper class to provide the number of spans each item occupies.
+     * <p>
+     * Default implementation sets each item to occupy exactly 1 span.
+     *
+     * @see GridLayoutManager#setSpanSizeLookup(SpanSizeLookup)
+     */
+    public abstract static class SpanSizeLookup {
+        final SparseIntArray mSpanIndexCache = new SparseIntArray();
+        private boolean mCacheSpanIndices = false;
+
+        /**
+         * Returns the number of span occupied by the item at <code>position</code>.
+         *
+         * @param position The adapter position of the item
+         * @return The number of spans occupied by the item at the provided position
+         */
+        public abstract int getSpanSize(int position);
+
+        /**
+         * Sets whether the results of {@link #getSpanIndex(int, int)} method should be cached or
+         * not. By default these values are not cached. If you are not overriding
+         * {@link #getSpanIndex(int, int)}, you should set this to true for better performance.
+         *
+         * @param cacheSpanIndices Whether results of getSpanIndex should be cached or not.
+         */
+        public void setSpanIndexCacheEnabled(boolean cacheSpanIndices) {
+            mCacheSpanIndices = cacheSpanIndices;
+        }
+
+        /**
+         * Clears the span index cache. GridLayoutManager automatically calls this method when
+         * adapter changes occur.
+         */
+        public void invalidateSpanIndexCache() {
+            mSpanIndexCache.clear();
+        }
+
+        /**
+         * Returns whether results of {@link #getSpanIndex(int, int)} method are cached or not.
+         *
+         * @return True if results of {@link #getSpanIndex(int, int)} are cached.
+         */
+        public boolean isSpanIndexCacheEnabled() {
+            return mCacheSpanIndices;
+        }
+
+        int getCachedSpanIndex(int position, int spanCount) {
+            if (!mCacheSpanIndices) {
+                return getSpanIndex(position, spanCount);
+            }
+            final int existing = mSpanIndexCache.get(position, -1);
+            if (existing != -1) {
+                return existing;
+            }
+            final int value = getSpanIndex(position, spanCount);
+            mSpanIndexCache.put(position, value);
+            return value;
+        }
+
+        /**
+         * Returns the final span index of the provided position.
+         * <p>
+         * If you have a faster way to calculate span index for your items, you should override
+         * this method. Otherwise, you should enable span index cache
+         * ({@link #setSpanIndexCacheEnabled(boolean)}) for better performance. When caching is
+         * disabled, default implementation traverses all items from 0 to
+         * <code>position</code>. When caching is enabled, it calculates from the closest cached
+         * value before the <code>position</code>.
+         * <p>
+         * If you override this method, you need to make sure it is consistent with
+         * {@link #getSpanSize(int)}. GridLayoutManager does not call this method for
+         * each item. It is called only for the reference item and rest of the items
+         * are assigned to spans based on the reference item. For example, you cannot assign a
+         * position to span 2 while span 1 is empty.
+         * <p>
+         * Note that span offsets always start with 0 and are not affected by RTL.
+         *
+         * @param position  The position of the item
+         * @param spanCount The total number of spans in the grid
+         * @return The final span position of the item. Should be between 0 (inclusive) and
+         * <code>spanCount</code>(exclusive)
+         */
+        public int getSpanIndex(int position, int spanCount) {
+            int positionSpanSize = getSpanSize(position);
+            if (positionSpanSize == spanCount) {
+                return 0; // quick return for full-span items
+            }
+            int span = 0;
+            int startPos = 0;
+            // If caching is enabled, try to jump
+            if (mCacheSpanIndices && mSpanIndexCache.size() > 0) {
+                int prevKey = findReferenceIndexFromCache(position);
+                if (prevKey >= 0) {
+                    span = mSpanIndexCache.get(prevKey) + getSpanSize(prevKey);
+                    startPos = prevKey + 1;
+                }
+            }
+            for (int i = startPos; i < position; i++) {
+                int size = getSpanSize(i);
+                span += size;
+                if (span == spanCount) {
+                    span = 0;
+                } else if (span > spanCount) {
+                    // did not fit, moving to next row / column
+                    span = size;
+                }
+            }
+            if (span + positionSpanSize <= spanCount) {
+                return span;
+            }
+            return 0;
+        }
+
+        int findReferenceIndexFromCache(int position) {
+            int lo = 0;
+            int hi = mSpanIndexCache.size() - 1;
+            while (lo <= hi) {
+                final int mid = (lo + hi) >>> 1;
+                final int midVal = mSpanIndexCache.keyAt(mid);
+                if (midVal < position) {
+                    lo = mid + 1;
+                } else {
+                    hi = mid - 1;
+                }
+            }
+            int index = lo - 1;
+            if (index >= 0 && index < mSpanIndexCache.size()) {
+                return mSpanIndexCache.keyAt(index);
+            }
+            return -1;
+        }
+
+        /**
+         * Returns the index of the group this position belongs.
+         * <p>
+         * For example, if grid has 3 columns and each item occupies 1 span, span group index
+         * for item 1 will be 0, item 5 will be 1.
+         *
+         * @param adapterPosition The position in adapter
+         * @param spanCount       The total number of spans in the grid
+         * @return The index of the span group including the item at the given adapter position
+         */
+        public int getSpanGroupIndex(int adapterPosition, int spanCount) {
+            int span = 0;
+            int group = 0;
+            int positionSpanSize = getSpanSize(adapterPosition);
+            for (int i = 0; i < adapterPosition; i++) {
+                int size = getSpanSize(i);
+                span += size;
+                if (span == spanCount) {
+                    span = 0;
+                    group++;
+                } else if (span > spanCount) {
+                    // did not fit, moving to next row / column
+                    span = size;
+                    group++;
+                }
+            }
+            if (span + positionSpanSize > spanCount) {
+                group++;
+            }
+            return group;
+        }
+    }
+
+    @Override
+    public boolean supportsPredictiveItemAnimations() {
+        return mPendingSavedState == null && !mPendingSpanCountChange;
+    }
+
+    /**
+     * Default implementation for {@link SpanSizeLookup}. Each item occupies 1 span.
+     */
+    public static final class DefaultSpanSizeLookup extends SpanSizeLookup {
+        @Override
+        public int getSpanSize(int position) {
+            return 1;
+        }
+
+        @Override
+        public int getSpanIndex(int position, int spanCount) {
+            return position % spanCount;
+        }
+    }
+
+    /**
+     * LayoutParams used by GridLayoutManager.
+     * <p>
+     * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the
+     * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is
+     * expected to fill all of the space given to it.
+     */
+    public static class LayoutParams extends RecyclerView.LayoutParams {
+        /**
+         * Span Id for Views that are not laid out yet.
+         */
+        public static final int INVALID_SPAN_ID = -1;
+        int mSpanIndex = INVALID_SPAN_ID;
+        int mSpanSize = 0;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(ViewGroup.MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(RecyclerView.LayoutParams source) {
+            super(source);
+        }
+
+        /**
+         * Returns the current span index of this View. If the View is not laid out yet, the return
+         * value is <code>undefined</code>.
+         * <p>
+         * Starting with RecyclerView <b>24.2.0</b>, span indices are always indexed from position 0
+         * even if the layout is RTL. In a vertical GridLayoutManager, <b>leftmost</b> span is span
+         * 0 if the layout is <b>LTR</b> and <b>rightmost</b> span is span 0 if the layout is
+         * <b>RTL</b>. Prior to 24.2.0, it was the opposite which was conflicting with
+         * {@link SpanSizeLookup#getSpanIndex(int, int)}.
+         * <p>
+         * If the View occupies multiple spans, span with the minimum index is returned.
+         *
+         * @return The span index of the View.
+         */
+        public int getSpanIndex() {
+            return mSpanIndex;
+        }
+
+        /**
+         * Returns the number of spans occupied by this View. If the View not laid out yet, the
+         * return value is <code>undefined</code>.
+         *
+         * @return The number of spans occupied by this View.
+         */
+        public int getSpanSize() {
+            return mSpanSize;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java
deleted file mode 100644
index d2a9072..0000000
--- a/core/java/com/android/internal/widget/SwipeDismissLayout.java
+++ /dev/null
@@ -1,516 +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.internal.widget;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.ContextWrapper;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ReceiverCallNotAllowedException;
-import android.content.res.TypedArray;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewGroup;
-import android.view.animation.DecelerateInterpolator;
-import android.widget.FrameLayout;
-
-/**
- * Special layout that finishes its activity when swiped away.
- */
-public class SwipeDismissLayout extends FrameLayout {
-    private static final String TAG = "SwipeDismissLayout";
-
-    private static final float MAX_DIST_THRESHOLD = .33f;
-    private static final float MIN_DIST_THRESHOLD = .1f;
-
-    public interface OnDismissedListener {
-        void onDismissed(SwipeDismissLayout layout);
-    }
-
-    public interface OnSwipeProgressChangedListener {
-        /**
-         * Called when the layout has been swiped and the position of the window should change.
-         *
-         * @param alpha A number in [0, 1] representing what the alpha transparency of the window
-         * should be.
-         * @param translate A number in [0, w], where w is the width of the
-         * layout. This is equivalent to progress * layout.getWidth().
-         */
-        void onSwipeProgressChanged(SwipeDismissLayout layout, float alpha, float translate);
-
-        void onSwipeCancelled(SwipeDismissLayout layout);
-    }
-
-    private boolean mIsWindowNativelyTranslucent;
-
-    // Cached ViewConfiguration and system-wide constant values
-    private int mSlop;
-    private int mMinFlingVelocity;
-
-    // Transient properties
-    private int mActiveTouchId;
-    private float mDownX;
-    private float mDownY;
-    private float mLastX;
-    private boolean mSwiping;
-    private boolean mDismissed;
-    private boolean mDiscardIntercept;
-    private VelocityTracker mVelocityTracker;
-    private boolean mBlockGesture = false;
-    private boolean mActivityTranslucencyConverted = false;
-
-    private final DismissAnimator mDismissAnimator = new DismissAnimator();
-
-    private OnDismissedListener mDismissedListener;
-    private OnSwipeProgressChangedListener mProgressListener;
-    private BroadcastReceiver mScreenOffReceiver;
-    private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
-
-
-    private boolean mDismissable = true;
-
-    public SwipeDismissLayout(Context context) {
-        super(context);
-        init(context);
-    }
-
-    public SwipeDismissLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init(context);
-    }
-
-    public SwipeDismissLayout(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-        init(context);
-    }
-
-    private void init(Context context) {
-        ViewConfiguration vc = ViewConfiguration.get(context);
-        mSlop = vc.getScaledTouchSlop();
-        mMinFlingVelocity = vc.getScaledMinimumFlingVelocity();
-        TypedArray a = context.getTheme().obtainStyledAttributes(
-                com.android.internal.R.styleable.Theme);
-        mIsWindowNativelyTranslucent = a.getBoolean(
-                com.android.internal.R.styleable.Window_windowIsTranslucent, false);
-        a.recycle();
-    }
-
-    public void setOnDismissedListener(OnDismissedListener listener) {
-        mDismissedListener = listener;
-    }
-
-    public void setOnSwipeProgressChangedListener(OnSwipeProgressChangedListener listener) {
-        mProgressListener = listener;
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        try {
-            mScreenOffReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    post(() -> {
-                        if (mDismissed) {
-                            dismiss();
-                        } else {
-                            cancel();
-                        }
-                        resetMembers();
-                    });
-                }
-            };
-            getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter);
-        } catch (ReceiverCallNotAllowedException e) {
-            /* Exception is thrown if the context is a ReceiverRestrictedContext object. As
-             * ReceiverRestrictedContext is not public, the context type cannot be checked before
-             * calling registerReceiver. The most likely scenario in which the exception would be
-             * thrown would be when a BroadcastReceiver creates a dialog to show the user. */
-            mScreenOffReceiver = null; // clear receiver since it was not used.
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mScreenOffReceiver != null) {
-            getContext().unregisterReceiver(mScreenOffReceiver);
-            mScreenOffReceiver = null;
-        }
-        super.onDetachedFromWindow();
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(MotionEvent ev) {
-        checkGesture((ev));
-        if (mBlockGesture) {
-            return true;
-        }
-        if (!mDismissable) {
-            return super.onInterceptTouchEvent(ev);
-        }
-
-        // Offset because the view is translated during swipe, match X with raw X. Active touch
-        // coordinates are mostly used by the velocity tracker, so offset it to match the raw
-        // coordinates which is what is primarily used elsewhere.
-        ev.offsetLocation(ev.getRawX() - ev.getX(), 0);
-
-        switch (ev.getActionMasked()) {
-            case MotionEvent.ACTION_DOWN:
-                resetMembers();
-                mDownX = ev.getRawX();
-                mDownY = ev.getRawY();
-                mActiveTouchId = ev.getPointerId(0);
-                mVelocityTracker = VelocityTracker.obtain("int1");
-                mVelocityTracker.addMovement(ev);
-                break;
-
-            case MotionEvent.ACTION_POINTER_DOWN:
-                int actionIndex = ev.getActionIndex();
-                mActiveTouchId = ev.getPointerId(actionIndex);
-                break;
-            case MotionEvent.ACTION_POINTER_UP:
-                actionIndex = ev.getActionIndex();
-                int pointerId = ev.getPointerId(actionIndex);
-                if (pointerId == mActiveTouchId) {
-                    // This was our active pointer going up. Choose a new active pointer.
-                    int newActionIndex = actionIndex == 0 ? 1 : 0;
-                    mActiveTouchId = ev.getPointerId(newActionIndex);
-                }
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP:
-                resetMembers();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                if (mVelocityTracker == null || mDiscardIntercept) {
-                    break;
-                }
-
-                int pointerIndex = ev.findPointerIndex(mActiveTouchId);
-                if (pointerIndex == -1) {
-                    Log.e(TAG, "Invalid pointer index: ignoring.");
-                    mDiscardIntercept = true;
-                    break;
-                }
-                float dx = ev.getRawX() - mDownX;
-                float x = ev.getX(pointerIndex);
-                float y = ev.getY(pointerIndex);
-                if (dx != 0 && canScroll(this, false, dx, x, y)) {
-                    mDiscardIntercept = true;
-                    break;
-                }
-                updateSwiping(ev);
-                break;
-        }
-
-        return !mDiscardIntercept && mSwiping;
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev) {
-        checkGesture((ev));
-        if (mBlockGesture) {
-            return true;
-        }
-        if (mVelocityTracker == null || !mDismissable) {
-            return super.onTouchEvent(ev);
-        }
-
-        // Offset because the view is translated during swipe, match X with raw X. Active touch
-        // coordinates are mostly used by the velocity tracker, so offset it to match the raw
-        // coordinates which is what is primarily used elsewhere.
-        ev.offsetLocation(ev.getRawX() - ev.getX(), 0);
-
-        switch (ev.getActionMasked()) {
-            case MotionEvent.ACTION_UP:
-                updateDismiss(ev);
-                if (mDismissed) {
-                    mDismissAnimator.animateDismissal(ev.getRawX() - mDownX);
-                } else if (mSwiping
-                        // Only trigger animation if we had a MOVE event that would shift the
-                        // underlying view, otherwise the animation would be janky.
-                        && mLastX != Integer.MIN_VALUE) {
-                    mDismissAnimator.animateRecovery(ev.getRawX() - mDownX);
-                }
-                resetMembers();
-                break;
-
-            case MotionEvent.ACTION_CANCEL:
-                cancel();
-                resetMembers();
-                break;
-
-            case MotionEvent.ACTION_MOVE:
-                mVelocityTracker.addMovement(ev);
-                mLastX = ev.getRawX();
-                updateSwiping(ev);
-                if (mSwiping) {
-                    setProgress(ev.getRawX() - mDownX);
-                    break;
-                }
-        }
-        return true;
-    }
-
-    private void setProgress(float deltaX) {
-        if (mProgressListener != null && deltaX >= 0)  {
-            mProgressListener.onSwipeProgressChanged(
-                    this, progressToAlpha(deltaX / getWidth()), deltaX);
-        }
-    }
-
-    private void dismiss() {
-        if (mDismissedListener != null) {
-            mDismissedListener.onDismissed(this);
-        }
-    }
-
-    protected void cancel() {
-        if (!mIsWindowNativelyTranslucent) {
-            Activity activity = findActivity();
-            if (activity != null && mActivityTranslucencyConverted) {
-                activity.convertFromTranslucent();
-                mActivityTranslucencyConverted = false;
-            }
-        }
-        if (mProgressListener != null) {
-            mProgressListener.onSwipeCancelled(this);
-        }
-    }
-
-    /**
-     * Resets internal members when canceling.
-     */
-    private void resetMembers() {
-        if (mVelocityTracker != null) {
-            mVelocityTracker.recycle();
-        }
-        mVelocityTracker = null;
-        mDownX = 0;
-        mLastX = Integer.MIN_VALUE;
-        mDownY = 0;
-        mSwiping = false;
-        mDismissed = false;
-        mDiscardIntercept = false;
-    }
-
-    private void updateSwiping(MotionEvent ev) {
-        boolean oldSwiping = mSwiping;
-        if (!mSwiping) {
-            float deltaX = ev.getRawX() - mDownX;
-            float deltaY = ev.getRawY() - mDownY;
-            if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) {
-                mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < Math.abs(deltaX);
-            } else {
-                mSwiping = false;
-            }
-        }
-
-        if (mSwiping && !oldSwiping) {
-            // Swiping has started
-            if (!mIsWindowNativelyTranslucent) {
-                Activity activity = findActivity();
-                if (activity != null) {
-                    mActivityTranslucencyConverted = activity.convertToTranslucent(null, null);
-                }
-            }
-        }
-    }
-
-    private void updateDismiss(MotionEvent ev) {
-        float deltaX = ev.getRawX() - mDownX;
-        // Don't add the motion event as an UP event would clear the velocity tracker
-        mVelocityTracker.computeCurrentVelocity(1000);
-        float xVelocity = mVelocityTracker.getXVelocity();
-        if (mLastX == Integer.MIN_VALUE) {
-            // If there's no changes to mLastX, we have only one point of data, and therefore no
-            // velocity. Estimate velocity from just the up and down event in that case.
-            xVelocity = deltaX / ((ev.getEventTime() - ev.getDownTime()) / 1000);
-        }
-        if (!mDismissed) {
-            // Adjust the distance threshold linearly between the min and max threshold based on the
-            // x-velocity scaled with the the fling threshold speed
-            float distanceThreshold = getWidth() * Math.max(
-                    Math.min((MIN_DIST_THRESHOLD - MAX_DIST_THRESHOLD)
-                            * xVelocity / mMinFlingVelocity // scale x-velocity with fling velocity
-                            + MAX_DIST_THRESHOLD, // offset to start at max threshold
-                            MAX_DIST_THRESHOLD), // cap at max threshold
-                    MIN_DIST_THRESHOLD); // bottom out at min threshold
-            if ((deltaX > distanceThreshold && ev.getRawX() >= mLastX)
-                    || xVelocity >= mMinFlingVelocity) {
-                mDismissed = true;
-            }
-        }
-        // Check if the user tried to undo this.
-        if (mDismissed && mSwiping) {
-            // Check if the user's finger is actually flinging back to left
-            if (xVelocity < -mMinFlingVelocity) {
-                mDismissed = false;
-            }
-        }
-    }
-
-    /**
-     * Tests scrollability within child views of v in the direction of dx.
-     *
-     * @param v View to test for horizontal scrollability
-     * @param checkV Whether the view v passed should itself be checked for scrollability (true),
-     *               or just its children (false).
-     * @param dx Delta scrolled in pixels. Only the sign of this is used.
-     * @param x X coordinate of the active touch point
-     * @param y Y coordinate of the active touch point
-     * @return true if child views of v can be scrolled by delta of dx.
-     */
-    protected boolean canScroll(View v, boolean checkV, float dx, float x, float y) {
-        if (v instanceof ViewGroup) {
-            final ViewGroup group = (ViewGroup) v;
-            final int scrollX = v.getScrollX();
-            final int scrollY = v.getScrollY();
-            final int count = group.getChildCount();
-            for (int i = count - 1; i >= 0; i--) {
-                final View child = group.getChildAt(i);
-                if (x + scrollX >= child.getLeft() && x + scrollX < child.getRight() &&
-                        y + scrollY >= child.getTop() && y + scrollY < child.getBottom() &&
-                        canScroll(child, true, dx, x + scrollX - child.getLeft(),
-                                y + scrollY - child.getTop())) {
-                    return true;
-                }
-            }
-        }
-
-        return checkV && v.canScrollHorizontally((int) -dx);
-    }
-
-    public void setDismissable(boolean dismissable) {
-        if (!dismissable && mDismissable) {
-            cancel();
-            resetMembers();
-        }
-
-        mDismissable = dismissable;
-    }
-
-    private void checkGesture(MotionEvent ev) {
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
-            mBlockGesture = mDismissAnimator.isAnimating();
-        }
-    }
-
-    private float progressToAlpha(float progress) {
-        return 1 - progress * progress * progress;
-    }
-
-    private Activity findActivity() {
-        Context context = getContext();
-        while (context instanceof ContextWrapper) {
-            if (context instanceof Activity) {
-                return (Activity) context;
-            }
-            context = ((ContextWrapper) context).getBaseContext();
-        }
-        return null;
-    }
-
-    private class DismissAnimator implements AnimatorUpdateListener, Animator.AnimatorListener {
-        private final TimeInterpolator DISMISS_INTERPOLATOR = new DecelerateInterpolator(1.5f);
-        private final long DISMISS_DURATION = 250;
-
-        private final ValueAnimator mDismissAnimator = new ValueAnimator();
-        private boolean mWasCanceled = false;
-        private boolean mDismissOnComplete = false;
-
-        /* package */ DismissAnimator() {
-            mDismissAnimator.addUpdateListener(this);
-            mDismissAnimator.addListener(this);
-        }
-
-        /* package */ void animateDismissal(float currentTranslation) {
-            animate(
-                    currentTranslation / getWidth(),
-                    1,
-                    DISMISS_DURATION,
-                    DISMISS_INTERPOLATOR,
-                    true /* dismiss */);
-        }
-
-        /* package */ void animateRecovery(float currentTranslation) {
-            animate(
-                    currentTranslation / getWidth(),
-                    0,
-                    DISMISS_DURATION,
-                    DISMISS_INTERPOLATOR,
-                    false /* don't dismiss */);
-        }
-
-        /* package */ boolean isAnimating() {
-            return mDismissAnimator.isStarted();
-        }
-
-        private void animate(float from, float to, long duration, TimeInterpolator interpolator,
-                boolean dismissOnComplete) {
-            mDismissAnimator.cancel();
-            mDismissOnComplete = dismissOnComplete;
-            mDismissAnimator.setFloatValues(from, to);
-            mDismissAnimator.setDuration(duration);
-            mDismissAnimator.setInterpolator(interpolator);
-            mDismissAnimator.start();
-        }
-
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            float value = (Float) animation.getAnimatedValue();
-            setProgress(value * getWidth());
-        }
-
-        @Override
-        public void onAnimationStart(Animator animation) {
-            mWasCanceled = false;
-        }
-
-        @Override
-        public void onAnimationCancel(Animator animation) {
-            mWasCanceled = true;
-        }
-
-        @Override
-        public void onAnimationEnd(Animator animation) {
-            if (!mWasCanceled) {
-                if (mDismissOnComplete) {
-                    dismiss();
-                } else {
-                    cancel();
-                }
-            }
-        }
-
-        @Override
-        public void onAnimationRepeat(Animator animation) {
-        }
-    }
-}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 30edc37..ea10949 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -179,6 +179,7 @@
                 "android_hardware_UsbRequest.cpp",
                 "android_hardware_location_ActivityRecognitionHardware.cpp",
                 "android_util_FileObserver.cpp",
+                "android/graphics/SurfaceTexture.cpp",
                 "android/opengl/poly_clip.cpp", // TODO: .arm
                 "android/opengl/util.cpp",
                 "android_server_NetworkManagementSocketTagger.cpp",
@@ -431,7 +432,6 @@
                 "android/graphics/GIFMovie.cpp",
                 "android/graphics/Movie.cpp",
                 "android/graphics/MovieImpl.cpp",
-                "android/graphics/SurfaceTexture.cpp",
                 "android/graphics/pdf/PdfDocument.cpp",
                 "android/graphics/pdf/PdfEditor.cpp",
                 "android/graphics/pdf/PdfRenderer.cpp",
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 11d321f..bc1cc09 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -158,6 +158,7 @@
 
 static jclass   gBitmapConfig_class;
 static jfieldID gBitmapConfig_nativeInstanceID;
+static jmethodID gBitmapConfig_nativeToConfigMethodID;
 
 static jclass   gBitmapRegionDecoder_class;
 static jmethodID gBitmapRegionDecoder_constructorMethodID;
@@ -345,6 +346,54 @@
     bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
 }
 
+AndroidBitmapFormat GraphicsJNI::getFormatFromConfig(JNIEnv* env, jobject jconfig) {
+    ALOG_ASSERT(env);
+    if (NULL == jconfig) {
+        return ANDROID_BITMAP_FORMAT_NONE;
+    }
+    ALOG_ASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
+    jint javaConfigId = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
+
+    const AndroidBitmapFormat config2BitmapFormat[] = {
+        ANDROID_BITMAP_FORMAT_NONE,
+        ANDROID_BITMAP_FORMAT_A_8,
+        ANDROID_BITMAP_FORMAT_NONE, // Previously Config.Index_8
+        ANDROID_BITMAP_FORMAT_RGB_565,
+        ANDROID_BITMAP_FORMAT_RGBA_4444,
+        ANDROID_BITMAP_FORMAT_RGBA_8888,
+        ANDROID_BITMAP_FORMAT_RGBA_F16,
+        ANDROID_BITMAP_FORMAT_NONE // Congfig.HARDWARE
+    };
+    return config2BitmapFormat[javaConfigId];
+}
+
+jobject GraphicsJNI::getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) {
+    ALOG_ASSERT(env);
+    jint configId = kNo_LegacyBitmapConfig;
+    switch (format) {
+      case ANDROID_BITMAP_FORMAT_A_8:
+        configId = kA8_LegacyBitmapConfig;
+        break;
+      case ANDROID_BITMAP_FORMAT_RGB_565:
+        configId = kRGB_565_LegacyBitmapConfig;
+        break;
+      case ANDROID_BITMAP_FORMAT_RGBA_4444:
+        configId = kARGB_4444_LegacyBitmapConfig;
+        break;
+      case ANDROID_BITMAP_FORMAT_RGBA_8888:
+        configId = kARGB_8888_LegacyBitmapConfig;
+        break;
+      case ANDROID_BITMAP_FORMAT_RGBA_F16:
+        configId = kRGBA_16F_LegacyBitmapConfig;
+        break;
+      default:
+        break;
+    }
+
+    return env->CallStaticObjectMethod(gBitmapConfig_class,
+                                       gBitmapConfig_nativeToConfigMethodID, configId);
+}
+
 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
     ALOG_ASSERT(env);
     if (NULL == jconfig) {
@@ -634,6 +683,9 @@
 
     gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config"));
     gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I");
+    gBitmapConfig_nativeToConfigMethodID = GetStaticMethodIDOrDie(env, gBitmapConfig_class,
+                                                                  "nativeToConfig",
+                                                                  "(I)Landroid/graphics/Bitmap$Config;");
 
     gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
     gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index f80651c..6e7d9e7 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -76,6 +76,8 @@
         or kUnknown_SkColorType if the java object is null.
     */
     static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig);
+    static AndroidBitmapFormat getFormatFromConfig(JNIEnv* env, jobject jconfig);
+    static jobject getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
 
     static bool isHardwareConfig(JNIEnv* env, jobject jconfig);
     static jint hardwareLegacyBitmapConfig();
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index c74c264..1a9e8d0 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -24,7 +24,9 @@
 #include <GLES2/gl2ext.h>
 
 #include <gui/Surface.h>
+#include <gui/surfacetexture/SurfaceTexture.h>
 #include <gui/BufferQueue.h>
+#include <gui/surfacetexture/surface_texture_platform.h>
 
 #include "core_jni_helpers.h"
 
@@ -35,7 +37,6 @@
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
 #include <nativehelper/ScopedLocalRef.h>
-#include "surfacetexture/SurfaceTexture.h"
 
 // ----------------------------------------------------------------------------
 
@@ -402,3 +403,6 @@
 }
 
 } // namespace android
+
+//TODO: Move this file to frameworks/base/core/jni/android_graphics_SurfaceTexture.cpp. See
+//TODO: android_view_Surface.cpp for example.
diff --git a/core/jni/android/graphics/apex/android_bitmap.cpp b/core/jni/android/graphics/apex/android_bitmap.cpp
index 96cc5db..a328def 100644
--- a/core/jni/android/graphics/apex/android_bitmap.cpp
+++ b/core/jni/android/graphics/apex/android_bitmap.cpp
@@ -17,6 +17,7 @@
 #include "android/graphics/bitmap.h"
 #include "Bitmap.h"
 #include "TypeCast.h"
+#include "GraphicsJNI.h"
 
 #include <hwui/Bitmap.h>
 
@@ -104,3 +105,11 @@
     }
     return bitmap->pixels();
 }
+
+AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj) {
+  return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj);
+}
+
+jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) {
+  return GraphicsJNI::getConfigFromFormat(env, format);
+}
diff --git a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
index bfa4c8d..dea5517 100644
--- a/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
+++ b/core/jni/android/graphics/apex/include/android/graphics/bitmap.h
@@ -38,6 +38,9 @@
 
 void* ABitmap_getPixels(ABitmap* bitmap);
 
+AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj);
+jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format);
+
 __END_DECLS
 
 #ifdef	__cplusplus
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 87adbe8..cb7f0dd 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -26,9 +26,9 @@
 #include "core_jni_helpers.h"
 #include "android_runtime/android_view_Surface.h"
 #include "android_runtime/android_graphics_SurfaceTexture.h"
-#include "surfacetexture/SurfaceTexture.h"
 
 #include <gui/Surface.h>
+#include <gui/surfacetexture/SurfaceTexture.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <gui/IProducerListener.h>
 #include <ui/GraphicBuffer.h>
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 6417b28..01f9d0b0 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2250,6 +2250,26 @@
     return (jint) check_AudioSystem_Command(AudioSystem::setRttEnabled(enabled));
 }
 
+static jint
+android_media_AudioSystem_setAudioHalPids(JNIEnv *env, jobject clazz, jintArray jPids)
+{
+    if (jPids == NULL) {
+        return (jint)AUDIO_JAVA_BAD_VALUE;
+    }
+    pid_t *nPidsArray = (pid_t *)env->GetIntArrayElements(jPids, NULL);
+    std::vector<pid_t> nPids(nPidsArray, nPidsArray + env->GetArrayLength(jPids));
+    status_t status = AudioSystem::setAudioHalPids(nPids);
+    env->ReleaseIntArrayElements(jPids, nPidsArray, 0);
+    jint jStatus = nativeToJavaStatus(status);
+    return jStatus;
+}
+
+static jboolean
+android_media_AudioSystem_isCallScreeningModeSupported(JNIEnv *env, jobject thiz)
+{
+    return AudioSystem::isCallScreenModeSupported();
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
@@ -2328,6 +2348,8 @@
                     (void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
     {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
     {"setRttEnabled",       "(Z)I",     (void *)android_media_AudioSystem_setRttEnabled},
+    {"setAudioHalPids",  "([I)I", (void *)android_media_AudioSystem_setAudioHalPids},
+    {"isCallScreeningModeSupported", "()Z", (void *)android_media_AudioSystem_isCallScreeningModeSupported},
 };
 
 static const JNINativeMethod gEventHandlerMethods[] = {
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 7582cae..4f3f283 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -23,8 +23,8 @@
 
 namespace {
 
-int getCanLoadSystemLibraries_native() {
-    return android::GraphicsEnv::getInstance().getCanLoadSystemLibraries();
+bool isDebuggable_native() {
+    return android::GraphicsEnv::getInstance().isDebuggable();
 }
 
 void setDriverPathAndSphalLibraries_native(JNIEnv* env, jobject clazz, jstring path,
@@ -94,7 +94,7 @@
 }
 
 const JNINativeMethod g_methods[] = {
-    { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
+    { "isDebuggable", "()Z", reinterpret_cast<void*>(isDebuggable_native) },
     { "setDriverPathAndSphalLibraries", "(Ljava/lang/String;Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPathAndSphalLibraries_native) },
     { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JJLjava/lang/String;I)V", reinterpret_cast<void*>(setGpuStats_native) },
     { "setInjectLayersPrSetDumpable", "()Z", reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native) },
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 3c0971b..5c4dc23 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -556,7 +556,9 @@
   assetmanager->SetConfiguration(configuration);
 }
 
-static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
+static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+                                                   jboolean includeOverlays,
+                                                   jboolean includeLoaders) {
   ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
 
   jobject sparse_array =
@@ -567,6 +569,10 @@
     return nullptr;
   }
 
+  // Optionally exclude overlays and loaders.
+  uint64_t exclusion_flags = ((includeOverlays) ? 0U : PROPERTY_OVERLAY)
+      | ((includeLoaders) ? 0U : PROPERTY_LOADER);
+
   assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) -> bool {
     jstring jpackage_name = env->NewStringUTF(package_name.c_str());
     if (jpackage_name == nullptr) {
@@ -577,7 +583,8 @@
     env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
                         jpackage_name);
     return true;
-  });
+  }, exclusion_flags);
+
   return sparse_array;
 }
 
@@ -1591,7 +1598,7 @@
     {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
     {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
      (void*)NativeSetConfiguration},
-    {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
+    {"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
      (void*)NativeGetAssignedPackageIdentifiers},
 
     // AssetManager file methods.
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d5cd278..f8a2744 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -274,7 +274,7 @@
 
 static jobject nativeCaptureLayers(JNIEnv* env, jclass clazz, jobject displayTokenObj,
         jlong layerObject, jobject sourceCropObj, jfloat frameScale,
-        jlongArray excludeObjectArray) {
+        jlongArray excludeObjectArray, jint format) {
 
     auto layer = reinterpret_cast<SurfaceControl *>(layerObject);
     if (layer == NULL) {
@@ -311,8 +311,9 @@
         dataspace = pickDataspaceFromColorMode(colorMode);
     }
     status_t res = ScreenshotClient::captureChildLayers(layer->getHandle(), dataspace,
-                                                        ui::PixelFormat::RGBA_8888, sourceCrop,
-                                                        excludeHandles, frameScale, &buffer);
+                                                        static_cast<ui::PixelFormat>(format),
+                                                        sourceCrop, excludeHandles, frameScale,
+                                                        &buffer);
     if (res != NO_ERROR) {
         return NULL;
     }
@@ -545,6 +546,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 +1317,8 @@
             (void*)nativeSetCornerRadius },
     {"nativeSetLayerStack", "(JJI)V",
             (void*)nativeSetLayerStack },
+    {"nativeSetShadowRadius", "(JJF)V",
+            (void*)nativeSetShadowRadius },
     {"nativeGetPhysicalDisplayIds", "()[J",
             (void*)nativeGetPhysicalDisplayIds },
     {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
@@ -1376,7 +1387,7 @@
             (void*)nativeScreenshot },
     {"nativeCaptureLayers",
             "(Landroid/os/IBinder;JLandroid/graphics/Rect;"
-            "F[J)"
+            "F[JI)"
             "Landroid/view/SurfaceControl$ScreenshotGraphicBuffer;",
             (void*)nativeCaptureLayers },
     {"nativeSetInputWindowInfo", "(JJLandroid/view/InputWindowHandle;)V",
diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp
index 8a3f540..6475151 100644
--- a/core/jni/android_view_TextureLayer.cpp
+++ b/core/jni/android_view_TextureLayer.cpp
@@ -23,7 +23,9 @@
 #include "core_jni_helpers.h"
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
-#include <gui/GLConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/surfacetexture/surface_texture_platform.h>
+#include <gui/surfacetexture/SurfaceTexture.h>
 #include <hwui/Paint.h>
 
 #include <SkMatrix.h>
@@ -64,7 +66,10 @@
 static void TextureLayer_setSurfaceTexture(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr, jobject surface) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    layer->setSurfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    auto consumer = SurfaceTexture_getSurfaceTexture(env, surface);
+    auto producer = SurfaceTexture_getProducer(env, surface);
+    layer->setSurfaceTexture(AutoTextureRelease(
+            ASurfaceTexture_create(consumer, producer)));
 }
 
 static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
diff --git a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
index d3ff959..e2d7891 100644
--- a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
+++ b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h
@@ -17,6 +17,8 @@
 #ifndef _ANDROID_GRAPHICS_SURFACETEXTURE_H
 #define _ANDROID_GRAPHICS_SURFACETEXTURE_H
 
+#include <utils/StrongPointer.h>
+
 #include "jni.h"
 
 namespace android {
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 b9d28e4..8f084ab 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -88,13 +88,15 @@
 message ActivityStackProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
-    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1;
+    // To be removed soon.
+    optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
     optional int32 id = 2;
     repeated TaskRecordProto tasks = 3;
     optional .com.android.server.wm.IdentifierProto resumed_activity = 4;
     optional int32 display_id = 5;
     optional bool fullscreen = 6;
     optional .android.graphics.RectProto bounds = 7;
+    optional .com.android.server.wm.StackProto stack = 8;
 }
 
 message TaskRecordProto {
diff --git a/core/proto/android/server/syncstorageengine.proto b/core/proto/android/server/syncstorageengine.proto
new file mode 100644
index 0000000..87eb1b3
--- /dev/null
+++ b/core/proto/android/server/syncstorageengine.proto
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto2";
+package com.android.server.content;
+import "frameworks/base/core/proto/android/privacy.proto";
+
+option java_multiple_files = true;
+
+/**
+ * Stores relevant information from a DayStats object in SyncStorageEngine.
+ */
+message SyncStatisticsProto {
+
+  message DayStats {
+    optional int32 day = 1; // day of the year - defined by SyncStorageEngine#getCurrentDayLocked()
+    optional int32 success_count = 2;
+    optional int64 success_time = 3; // time since epoch
+    optional int32 failure_count = 4;
+    optional int64 failure_time = 5; // time since epoch
+  }
+
+  repeated DayStats stats = 1;
+}
+
+/**
+ * Stores relevant information from a SyncStatusInfo object.
+ */
+message SyncStatusProto {
+
+  message StatusInfo {
+
+    message Stats {
+      optional int64 total_elapsed_time = 1; // time since epoch
+      optional int32 num_syncs = 2;
+      optional int32 num_failures = 3;
+      optional int32 num_cancels = 4;
+      optional int32 num_source_other = 5;
+      optional int32 num_source_local = 6;
+      optional int32 num_source_poll = 7;
+      optional int32 num_source_user = 8;
+      optional int32 num_source_periodic = 9;
+      optional int32 num_source_feed = 10;
+    }
+
+    message LastEventInfo {
+      optional int64 last_event_time = 1; // time since epoch
+      optional string last_event = 2;
+    }
+
+    // Note: version doesn't need to be stored in proto because of how protos store information but
+    // leaving field number 1 open in case we find a usage for it in the future.
+    optional int32 authority_id = 2;
+    optional int64 last_success_time = 3; // time since epoch
+    optional int32 last_success_source = 4;
+    optional int64 last_failure_time = 5; // time since epoch
+    optional int32 last_failure_source = 6;
+    optional string last_failure_message = 7;
+    optional int64 initial_failure_time = 8; // time since epoch
+    optional bool pending = 9;
+    optional bool initialize = 10;
+    repeated int64 periodic_sync_times = 11; // times since epoch
+    repeated LastEventInfo last_event_info = 12;
+    optional int64 last_today_reset_time = 13; // time since epoch
+    optional Stats total_stats = 14;
+    optional Stats today_stats = 15;
+    optional Stats yesterday_stats = 16;
+    repeated int64 per_source_last_success_times = 17; // times since epoch
+    repeated int64 per_source_last_failure_times = 18; // times since epoch
+  }
+
+  repeated StatusInfo status = 1;
+}
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c9a1829..653d381 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -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/tests/WindowManagerStressTest/Android.bp b/core/proto/android/stats/textclassifier/Android.bp
similarity index 74%
rename from tests/WindowManagerStressTest/Android.bp
rename to core/proto/android/stats/textclassifier/Android.bp
index 98749a7..bf90227 100644
--- a/tests/WindowManagerStressTest/Android.bp
+++ b/core/proto/android/stats/textclassifier/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2016 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.
@@ -12,10 +11,13 @@
 // WITHOUT 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,
-}
+java_library_static {
+    name: "textclassifierprotoslite",
+    proto: {
+        type: "lite",
+    },
+    srcs: [
+        "*.proto",
+    ],
+}
\ No newline at end of file
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b357b3e..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" />
 
@@ -4658,7 +4658,7 @@
         of this permission are REQUIRED to themselves check that the caller has
         PACKAGE_USAGE_STATS and OP_GET_USAGE_STATS. -->
     <permission android:name="android.permission.PEEK_DROPBOX_DATA"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature" />
 
     <application android:process="system"
                  android:persistent="true"
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 17b5f50..6807f9a 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -55,15 +55,14 @@
                   android:layout_centerHorizontal="true"/>
     </RelativeLayout>
 
-    <ListView
+    <com.android.internal.widget.RecyclerView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:layoutManager="com.android.internal.widget.GridLayoutManager"
         android:id="@+id/resolver_list"
         android:clipToPadding="false"
         android:background="?attr/colorBackgroundFloating"
         android:scrollbars="none"
-        android:listSelector="@color/transparent"
-        android:divider="@null"
         android:elevation="1dp"
         android:nestedScrollingEnabled="true"/>
 
diff --git a/core/res/res/layout/screen_swipe_dismiss.xml b/core/res/res/layout/screen_swipe_dismiss.xml
deleted file mode 100644
index 90e970fe..0000000
--- a/core/res/res/layout/screen_swipe_dismiss.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<!--
-This is a layout for a window whose resident activity is finished when swiped away.
--->
-
-<com.android.internal.widget.SwipeDismissLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@android:id/content"
-    android:fitsSystemWindows="true"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7f72a13..485162c 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Wekkerklanke"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Kennisgewingsklanke"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi netwerke beskikbaar</item>
-      <item quantity="one">Wi-Fi-netwerk beskikbaar</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Oop Wi-Fi-netwerke beskikbaar</item>
-      <item quantity="one">Oop Wi-Fi-netwerk beskikbaar</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Koppel aan oop Wi-Fi-netwerk"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Koppel tans aan Wi-Fi-netwerk"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Aan Wi-Fi-netwerk gekoppel"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Kon nie aan Wi-Fi-netwerk koppel nie"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tik om alle netwerke te sien"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Koppel"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alle netwerke"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Laat voorgestelde Wi‑Fi-netwerke toe?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Netwerke wat deur <xliff:g id="NAME">%s</xliff:g> voorgestel is. Toestel sal dalk outomaties koppel."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Laat toe"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nee, dankie"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi sal outomaties aanskakel"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Wanneer jy naby \'n gestoorde hoëgehaltenetwerk is"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Moenie weer aanskakel nie"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi is outomaties aangeskakel"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Jy is naby \'n gestoorde netwerk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Meld aan by Wi-Fi-netwerk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Meld by netwerk aan"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Gekoppel"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> het beperkte konnektiwiteit"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tik om in elk geval te koppel"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Veranderings aan jou warmkolinstellings"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Jou warmkolband het verander."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Hierdie toestel steun nie jou voorkeur vir net 5 GHz nie. Hierdie toestel sal in plaas daarvan die 5 GHz-band gebruik wanneer dit beskikbaar is."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Het oorgeskakel na <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Toestel gebruik <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internettoegang het nie. Heffings kan geld."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Het oorgeskakel van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"\'n onbekende netwerktipe"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" het \'n swak internetverbinding."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Laat verbinding toe?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Program %1$s wil aan Wi-Fi-netwerk %2$s koppel"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"\'n Program"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kon nie Wi-Fi Direct begin nie."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tik vir instellings"</string>
     <string name="accept" msgid="1645267259272829559">"Aanvaar"</string>
     <string name="decline" msgid="2112225451706137894">"Weier"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging gestuur"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Uitnodiging om te koppel"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Van:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Aan:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Die tablet sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Jou Android TV-toestel sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Die foon sal tydelik van Wi-Fi ontkoppel terwyl dit aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gekoppel is"</string>
     <string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; stuur \'n groot aantal SMS-boodskappe. Wil jy hierdie program toelaat om voort te gaan om boodskappe te stuur?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Batterybespaarder skakel agtergrondaktiwiteit, sommige visuele effekte en ander hoëkrag-kenmerke af of beperk dit om batteryleeftyd te verleng. "<annotation id="url">"Kom meer te wete"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Batterybespaarder skakel agtergrondaktiwiteit, sommige visuele effekte en ander hoëkrag-kenmerke af of beperk dit om batteryleeftyd te verleng."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 f576d04..f0a4307 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"የማንቂያ ድምጾች"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"የማሳወቂያ ድምፆች"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ያልታወቀ"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">የWi-Fi አውታረ መረቦች አሉ</item>
-      <item quantity="other">የWi-Fi አውታረ መረቦች አሉ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
-      <item quantity="other">የሚገኙ የWi-Fi አውታረ መረቦችን ክፈት</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ከክፍት የWi‑Fi አውታረ መረብ ጋር ያገናኙ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ከWi‑Fi አውታረ መረብ ጋር በመገናኘት ላይ"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ከWi‑Fi አውታረ መረብ ጋር ተገናኝቷል"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ከWi‑Fi አውታረ መረብ ጋር መገናኘት አልተቻለም"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ሁሉንም አውታረ መረቦችን ለማየት መታ ያድርጉ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"አገናኝ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ሁሉም አውታረ መረቦች"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"የተጠቆሙ የWi‑Fi አውታረ መረቦች ይፈቀዱ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"በ<xliff:g id="NAME">%s</xliff:g> የተጠቆሙ አውታረ መረቦች። መሣሪያ በራስ-ሰር ሊገናኝ ይችላል።"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ፍቀድ"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"አይ፣ አመሰግናለሁ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi በራስ-ሰር ይበራል"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ከፍተኛ ጥራት ያለው የተቀመጠ አውታረ መረብ አቅራቢያ ሲሆኑ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"መልሰህ አታብራ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi በራስ-ሰር በርቷል"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ከተቀመጠ አውታረ መረብ አቅራቢያ ነዎት፦ <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ወደ Wi-Fi አውታረ መረብ በመለያ ግባ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ወደ አውታረ መረብ በመለያ ይግቡ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ተገናኝቷል"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> የተገደበ ግንኙነት አለው"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ለማንኛውም ለማገናኘት መታ ያድርጉ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"በእርስዎ ሆትስፖት ቅንብሮች ላይ ለውጦች"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"የእርስዎ ሆትስፖት ባንድ ተለውጧል።"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ይህ መሣሪያ የእርስዎን ምርጫ ለ5GHz ብቻ አይደግፍም። በምትኩ፣ ይህ መሣሪያ ሲገኝ 5GHz ባንድ ይጠቀማል።"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"ወደ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ተቀይሯል"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ምንም ዓይነት የበይነመረብ ግንኙነት በማይኖረው ጊዜ መሣሪያዎች <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ን ይጠቀማሉ። ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ።"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"ከ<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ወደ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ተቀይሯል"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"አንድ ያልታወቀ አውታረ መረብ ዓይነት"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ደካማ የበይነመረብ ግንኙነት ኣለው፡፡"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ግንኙነት ይፈቀድ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"መተግበሪያ %1$s ወደ Wifi Network %2$s መገናኘት ይፈልጋል"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"አንድ መተግበሪያ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ  ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ  ያጠፋል።"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"በቀጥታ Wi-Fi ማስጀመር አልተቻለም።"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ለቅንብሮች መታ ያድርጉ"</string>
     <string name="accept" msgid="1645267259272829559">"ተቀበል"</string>
     <string name="decline" msgid="2112225451706137894">"ውድቅ አድርግ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ግብዣ ተልኳል"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ለማገናኘት ግብዣ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ከ፦"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ለ፦"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ጡባዊው ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ይላቀቃል"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ወደ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ተገናኝቶ ሳለ የእርስዎ Android TV መሣሪያ ለጊዜው ከ Wi-Fi ግንኙነቱ ይቋረጣል"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ስልኩ ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ተገናኝቶ ባለበት ጊዜ በጊዜያዊነት ከWi-Fi ጋር ያለው ግንኙነት ይቋረጣል"</string>
     <string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ቁጥራቸው ብዙ የሆኑ የኤስ.ኤም.ኤስ. መልዕክቶችን እየላከ ነው። ይሄ መተግበሪያ መልዕክቶችን መላኩን እንዲቀጥል መፍቀድ ትፈልጋለህ?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"የባትሪ ቆጣቢ ጠፍቷል ወይም የበስተጀርባ እንቅስቃሴን ይገድባል፣ አንዳንድ የሚታዩ ነገሮች ማሳመሪያዎች እና ሌሎች ለማራዘም ከፍተኛ ኃይል የሚጠቀሙ ባህሪያትን ይገድባል። "<annotation id="url">"የበለጠ ለመረዳት"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"የባትሪ ቆጣቢ ጠፍቷል ወይም የበስተጀርባ እንቅስቃሴን ይገድባል፣ አንዳንድ የሚታዩ ነገሮች ማሳመሪያዎች እና ሌሎች ለማራዘም ከፍተኛ ኃይል የሚጠቀሙ ባህሪያትን ይገድባል።"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 7974a08..4ecf6e7 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1324,38 +1324,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"أصوات التنبيه"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"أصوات الإشعار"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"غير معروف"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="zero">‏لا تتوفر أي شبكات Wi-Fi</item>
-      <item quantity="two">‏تتوفر شبكتا Wi-Fi</item>
-      <item quantity="few">‏تتوفر شبكات Wi-Fi</item>
-      <item quantity="many">‏تتوفر شبكات Wi-Fi</item>
-      <item quantity="other">‏تتوفر شبكات Wi-Fi</item>
-      <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="zero">‏لا تتوفر أي شبكات Wi-Fi مفتوحة</item>
-      <item quantity="two">‏تتوفر شبكتا Wi-Fi مفتوحتان</item>
-      <item quantity="few">‏تتوفر شبكات Wi-Fi مفتوحة</item>
-      <item quantity="many">‏تتوفر شبكات Wi-Fi مفتوحة</item>
-      <item quantity="other">‏تتوفر شبكات Wi-Fi مفتوحة</item>
-      <item quantity="one">‏تتوفر شبكة Wi-Fi واحدة مفتوحة</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"‏الاتصال بشبكة Wi-Fi المفتوحة"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"‏جارٍ الاتصال بشبكة Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"‏تم الاتصال بشبكة Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"‏تعذَّر الاتصال بشبكة Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"انقر للاطلاع على جميع الشبكات"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"اتصال"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"جميع الشبكات"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"‏هل تريد السماح لشبكات Wi‑Fi المقترحة؟"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"شبكات <xliff:g id="NAME">%s</xliff:g> المقترحة - قد يتم توصيل الجهاز تلقائيًا."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"سماح"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"لا، شكرًا"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"‏سيتم تشغيل شبكة Wi-Fi تلقائيًا."</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"عندما تكون بالقرب من شبكة محفوظة عالية الجودة"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"عدم إعادة التشغيل"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"‏تم تفعيل شبكة Wi-Fi تلقائيًا."</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"أنت قريب من شبكة محفوظة: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>."</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏تسجيل الدخول إلى شبكة Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"تسجيل الدخول إلى الشبكة"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1368,9 +1336,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"تمّ الاتصال."</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"إمكانية اتصال <xliff:g id="NETWORK_SSID">%1$s</xliff:g> محدودة."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"يمكنك النقر للاتصال على أي حال."</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"التغييرات التي طرأت على إعدادات نقطة الاتصال"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"تمّ تغيير نطاق نقطة الاتصال الخاصة بك."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"لا يتوافق هذا الجهاز مع إعدادك المفضّل الخاص باستخدام النطاق 5 غيغاهرتز فقط. وسيستخدم الجهاز بدلاً من ذلك النطاق 5 غيغاهرتز عندما يكون متاحًا."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"تم التبديل إلى <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"يستخدم الجهاز <xliff:g id="NEW_NETWORK">%1$s</xliff:g> عندما لا يتوفر اتصال بالإنترنت في شبكة <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>، ويمكن أن يتم فرض رسوم مقابل ذلك."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"تم التبديل من <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> إلى <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1382,27 +1347,8 @@
     <item msgid="8257233890381651999">"‏شبكة افتراضية خاصة (VPN)"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبكة غير معروف"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏تعذر الاتصال بـ Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" تحتوي على اتصال إنترنت ضعيف."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"هل تريد السماح بالاتصال؟"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏يريد تطبيق %1$s الاتصال بشبكة Wifi ‏%2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"تطبيق"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏اتصال Wi-Fi مباشر"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏تعذر بدء Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"‏تم تشغيل اتصال Wi-Fi المباشر"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"انقر للحصول على الإعدادات."</string>
     <string name="accept" msgid="1645267259272829559">"قبول"</string>
     <string name="decline" msgid="2112225451706137894">"رفض"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"تم إرسال الدعوة"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"دعوة للاتصال"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"من:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"إلى:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"‏اكتب رمز PIN المطلوب:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"‏سيتم قطع اتصال الجهاز اللوحي مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"‏سيتم قطع اتصال جهاز Android TV بشبكة Wi-Fi مؤقتًا أثناء اتصاله بجهاز<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"‏سيتم قطع اتصال الهاتف مؤقتًا بشبكة Wi-Fi في الوقت الذي يكون فيه متصلاً بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"‏إرسال رسائل قصيرة SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; يرسل عددًا كبيرًا من الرسائل القصيرة SMS. هل تريد السماح لهذا التطبيق بالاستمرار في إرسال الرسائل؟"</string>
@@ -1917,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"لإطالة عمر البطارية، تساعد ميزة \"توفير شحن البطارية\" على إيقاف أو تقييد نشاط الخلفية وبعض التأثيرات المرئية وغيرها من الميزات التي تستنفد طاقة البطارية. "<annotation id="url">"مزيد من المعلومات"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"لإطالة عمر البطارية، تساعد ميزة \"توفير شحن البطارية\" على إيقاف أو تقييد النشاط في الخلفية وبعض التأثيرات المرئية وغيرها من الميزات التي تستنفد طاقة البطارية."</string>
+    <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>
@@ -2195,4 +2141,23 @@
     </plurals>
     <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 8558d7c..81a04b7 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"এলার্মৰ ধ্বনিসমূহ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"জাননীৰ ধ্বনিসমূহ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"অজ্ঞাত"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
-      <item quantity="other">ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">পাছৱৰ্ড অবিহনে সংযোগ কৰিব পৰা ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
-      <item quantity="other">পাছৱৰ্ড অবিহনে সংযোগ কৰিব পৰা ৱাই-ফাই নেটৱর্ক উপলব্ধ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"পাছৱৰ্ড অবিহনে সংযোগ কৰিবপৰা ৱাই-ফাই নেটৱর্কৰ সৈতে সংযোগ কৰক"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ৱাই-ফাই নেটৱৰ্কৰ সৈতে সংযোগ কৰি থকা হৈছে"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ৱাই-ফাই নেটৱৰ্কৰ সৈতে সংযোগ কৰা হ’ল"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ৱাই-ফাই নেটৱৰ্কৰ সৈতে সংযোগ কৰিবপৰা নগ\'ল"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"সকলো নেটৱৰ্ক চাবলৈ টিপক"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"সংযোগ কৰক"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"সকলো নেটৱৰ্ক"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"পৰামর্শ হিচাপে পোৱা নেটৱর্কবোৰক অনুমতি দিবনে?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g>এ পৰামর্শ হিচাপে দিয়া নেটৱর্কবোৰ। ডিভাইচটো স্বয়ংক্ৰিয়ভাৱে সংযোগ হ\'ব পাৰে।"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"অনুমতি দিয়ক"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"নালাগে, ধন্যবাদ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে অন হ\'ব"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"যেতিয়া আপুনি ছেভ কৰি থোৱা উচ্চ মানৰ নেটৱৰ্কৰ কাষত থাকে"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"পুনৰাই অন নকৰিব"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ৱাই-ফাই স্বয়ংক্ৰিয়ভাৱে অন কৰা হ’ল"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"আপুনি ছেভ কৰি থোৱা নেটৱৰ্ক এটাৰ কাষত আছে: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ৱাই-ফাই নেটৱৰ্কত ছাইন ইন কৰক"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটৱৰ্কত ছাইন ইন কৰক"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"সংযোগ কৰা হ’ল"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ৰ সকলো সেৱাৰ এক্সেছ নাই"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"যিকোনো প্ৰকাৰে সংযোগ কৰিবলৈ টিপক"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"আপোনাৰ হটস্পট ছেটিংসমূহত কৰা সালসলনি"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপোনাৰ হটস্পটৰ বেণ্ড সলনি কৰা হ’ল।"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"আপোনাৰ কেৱল ৫গিগাহাৰ্টজৰ প্ৰতি অগ্ৰাধিকাৰ এই ডিভাচইচটোৱে সমৰ্থন নকৰে। ইয়াৰ পৰিৱৰ্তে, ডিভাচইচটোৱে যেতিয়া ৫গিগাহাৰ্টজ বেণ্ড উপলব্ধ হ’ব তেতিয়া সেইয়া ব্যৱহাৰ কৰিব।"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>লৈ সলনি কৰা হ’ল"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"যেতিয়া <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ত ইণ্টাৰনেট নাথাকে, তেতিয়া ডিভাইচে <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ক ব্যৱহাৰ কৰে। মাচুল প্ৰযোজ্য হ\'ব পাৰে।"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>ৰ পৰা <xliff:g id="NEW_NETWORK">%2$s</xliff:g> লৈ সলনি কৰা হ’ল"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"ভিপিএন"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"অজ্ঞাত প্ৰকাৰৰ নেটৱৰ্ক"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ৱাই-ফাইৰ লগত সংযোগ কৰিব পৰা নগ\'ল"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ইণ্টাৰনেট সংযোগ যথেষ্ট দুর্বল।"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগ কৰাৰ অনুমতি দিবনে?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s এপ্লিকেশ্বনটোৱে ৱাই-ফাই নেটৱৰ্ক %2$sৰ সৈতে সংযুক্ত হ\'ব বিচাৰিছে"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"এপ্লিকেশ্বন"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ৱাই-ফাই ডাইৰেক্ট"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ৱাই-ফাই ডাইৰেক্ট আৰম্ভ কৰক। এই কার্যই ৱাই-ফাই ক্লাইণ্ট/হটস্পট অফ কৰিব।"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ৱাই-ফাই ডাইৰেক্ট আৰম্ভ কৰিব পৰা নগ\'ল।"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ৱাই-ফাই ডাইৰেক্ট অন হৈ আছে"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ছেটিংসমূহৰ বাবে টিপক"</string>
     <string name="accept" msgid="1645267259272829559">"স্বীকাৰ কৰক"</string>
     <string name="decline" msgid="2112225451706137894">"প্ৰত্যাখ্যান কৰক"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"আমন্ত্ৰণ পঠোৱা হ’ল"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"সংযোগ হ\'বলৈ আমন্ত্ৰণ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"প্ৰেৰক:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"প্ৰতি:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"প্ৰয়োজনীয় পিন নম্বৰটো লিখক:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"পিন:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"টি.ভি.টো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হৈ থকাৰ অৱস্থাত অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ\'ব"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"আপোনাৰ Android TV ডিভাইচটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ৰ লগত সংযোগ হ’লে অস্থায়ীভাৱে ৱাই-ফাইৰ পৰা সংযোগ বিচ্ছিন্ন হ’ব"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ফ\'নটো <xliff:g id="DEVICE_NAME">%1$s</xliff:g> লৈ সংযোগ হ\'লে ৱাই-ফাইৰ পৰা কিছু সময়ৰ বাবে সংযোগ স্বীকাৰ বিচ্ছিন্ন হ\'ব"</string>
     <string name="select_character" msgid="3365550120617701745">"বর্ণ লিখক"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"এছএমএছ বার্তাবোৰ পঠিয়াই থকা হৈছে"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; এ বহু সংখ্যক এছএমএছ বার্তাবোৰ প্ৰেৰণ কৰি আছে। আপুনি এই এপে বার্তা প্ৰেৰণ কৰি থকাটো বিচাৰেনে?"</string>
@@ -1817,8 +1771,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"বেটাৰি সঞ্চয়কাৰীয়ে বেটাৰিৰ জীৱনকাল বৃদ্ধি কৰিবলৈ নেপথ্যৰ কাৰ্যকলাপ, ভিজুৱেল এফেক্ট আৰু অন্য অধিক বেটাৰি ব্যয় হোৱা সুবিধাবোৰ বন্ধ কৰে বা বাধা দিয়ে। "<annotation id="url">"অধিক জানক"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"বেটাৰি সঞ্চয়কাৰীয়ে বেটাৰিৰ জীৱনকাল বৃদ্ধি কৰিবলৈ নেপথ্যৰ কাৰ্যকলাপ, ভিজুৱেল এফেক্ট আৰু অন্য অধিক বেটাৰি ব্যয় হোৱা সুবিধাবোৰ বন্ধ কৰে বা বাধা দিয়ে।"</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 5b135cf..9f43c36 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zəngli saat səsləri"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildiriş səsləri"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Naməlum"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Əlçatan Wi-Fi şəbəkələri</item>
-      <item quantity="one">Əlçatan Wi-Fi şəbəkəsi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Əlçatan açıq Wi-Fi şəbəkələri</item>
-      <item quantity="one">Əlçatan açıq Wi-Fi şəbəkəsi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Açıq Wi‑Fi şəbəkəsinə qoşulun"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi şəbəkəsinə qoşulur"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi şəbəkəsinə qoşuldu"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi şəbəkəsinə qoşulmaq mümkün deyil"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Bütün şəbəkələri görmək üçün klikləyin"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Qoşulun"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Bütün şəbəkələr"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Təklif edilən Wi‑Fi şəbəkələrinə icazə verilsin?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> təklif edilən şəbəkə. Cihaz avtomatik qoşula bilər."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"İcazə verin"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Xeyr, təşəkkürlər"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi avtomatik olaraq aktiv ediləcək"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Yadda saxlanmış yüksək keyfiyyətli şəbəkələr yaxınlıqda olduqda"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Yenidən aktiv etməyin"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi avtomatik aktiv edildi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Yadda saxlanmış şəbəkəyə yaxınsınız: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi şəbəkəsinə daxil ol"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Şəbəkəyə daxil olun"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Qoşuldu"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> bağlantını məhdudlaşdırdı"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"İstənilən halda klikləyin"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot ayarlarınızda dəyişiklik"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot qrupu dəyişdi."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Bu cihaz yalnız 5GHz üçün tərcihinizi dəstəkləmir. Əvəzinə əlçatan olduqda bu cihaz 5GHz qrupundan istifadə edəcək."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> şəbəkə növünə keçirildi"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> şəbəkəsinin internetə girişi olmadıqda, cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> şəbəkəsini istifadə edir. Xidmət haqqı tutula bilər."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> şəbəkəsindən <xliff:g id="NEW_NETWORK">%2$s</xliff:g> şəbəkəsinə keçirildi"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"naməlum şəbəkə növü"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi\'a qoşulmaq alınmadı"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" zəif internet əlaqəsi var"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya icazə verilsin?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Proqram %1$s Wifi Şəbəkəsinə qoşulmaq istəyir %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Tətbiq"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct əməliyyatını başlat. Bu Wi-Fi müştəri/hotspotu bağlayacaq."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct başladıla bilmədi."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct aktivdir"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Ayarlar üçün tıklayın"</string>
     <string name="accept" msgid="1645267259272829559">"Qəbul edin"</string>
     <string name="decline" msgid="2112225451706137894">"İmtina edin"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Dəvətnamə göndərildi"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Qoşulmaq üçün dəvət"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdən:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kimə:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Tələb olunan PİN kodu daxil edin:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PİN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Bu planşet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulan zaman Wi-Fi şəbəkəsindən müvəqqəti ayrılmış olacaq"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşularkən Wi-Fi bağlantısı müvəqqəti olaraq kəsiləcək."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Bu telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazına qoşulan zaman Wi-Fi şəbəkəsindən müvəqqəti ayrılmış olacaq"</string>
     <string name="select_character" msgid="3365550120617701745">"Simvol daxil edin"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS mesaj göndərilir"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çox sayda SMS mesaj göndərir. Bu tətbiqin mesaj göndərməyə davam etməsinə icazə verirsiniz?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Enerjiyə qənaət batareya istifadəsini artırmaq üçün arxa fon fəaliyyətini, bəzi vizual effektləri və batareyadan çox istifadə edən digər funksiyalarını deaktiv edir və ya məhdudlaşdırır. "<annotation id="url">"Ətraflı məlumat"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Enerjiyə qənaət batareya istifadəsini artırmaq üçün arxa fon fəaliyyətini, bəzi vizual effektləri və batareyadan çox istifadə edən digər funksiyalarını deaktiv edir və ya məhdudlaşdırır."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 02b098f..a6ad733 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -48,7 +48,7 @@
     <string name="invalidPin" msgid="3850018445187475377">"Otkucajte PIN koji ima od 4 do 8 brojeva."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"Unesite PUK koji se sastoji od 8 cifara ili više."</string>
     <string name="needPuk" msgid="919668385956251611">"SIM kartica je zaključana PUK kodom. Unesite PUK kôd da biste je otključali."</string>
-    <string name="needPuk2" msgid="4526033371987193070">"Unesite PUK2 da biste deblokirali SIM karticu."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"Unesite PUK2 da biste odblokirali SIM karticu."</string>
     <string name="enablePin" msgid="209412020907207950">"Nije uspelo. Omogućite zaključavanje SIM/RUIM kartice."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
       <item quantity="one">Imate još <xliff:g id="NUMBER_1">%d</xliff:g> pokušaj pre nego što se SIM kartica zaključa.</item>
@@ -1264,32 +1264,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuci alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuci obaveštenja"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Wi-Fi mreže su dostupne</item>
-      <item quantity="few">Wi-Fi mreže su dostupne</item>
-      <item quantity="other">Wi-Fi mreže su dostupne</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Otvorene Wi-Fi mreže su dostupne</item>
-      <item quantity="few">Otvorene Wi-Fi mreže su dostupne</item>
-      <item quantity="other">Otvorene Wi-Fi mreže su dostupne</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Povežite se sa otvorenom Wi‑Fi mrežom"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Povezuje se sa Wi-Fi mrežom..."</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Povezali ste se sa Wi‑Fi mrežom"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Povezivanje sa Wi‑Fi mrežom nije uspelo"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Dodirnite da biste videli sve mreže"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Poveži"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Sve mreže"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Želite da dozvolite predložene Wi‑Fi mreže?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Mreže koje predlaže <xliff:g id="NAME">%s</xliff:g>. Uređaj će se možda povezati automatski."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Dozvoli"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, hvala"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi će se automatski uključiti"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kada ste u blizini sačuvane mreže visokog kvaliteta"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ne uključuj ponovo"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi je automatski uključen"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"U blizini ste sačuvane mreže: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijavite se na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1302,9 +1276,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano je"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu vezu"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da biste se ipak povezali"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promene podešavanja za hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Opseg hotspota je promenjen."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava podešavanje samo za 5 GHz. Uređaj će koristiti opseg od 5 GHz kada bude dostupan."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Prešli ste na tip mreže <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Uređaj koristi tip mreže <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kada tip mreže <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu. Možda će se naplaćivati troškovi."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prešli ste sa tipa mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na tip mreže <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,27 +1287,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznat tip mreže"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internet vezu."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi da se poveže na Wi-Fi mrežu %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokrenite Wi-Fi Direct. Time ćete isključiti klijenta/hotspot za Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nije moguće pokrenuti Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je uključen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dodirnite za podešavanja"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
     <string name="decline" msgid="2112225451706137894">"Odbij"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslata"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozivnica za povezivanje"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kome:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Unesite potrebni PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će privremeno prekinuti vezu sa Wi-Fi-jem dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV uređaj će privremeno prekinuti vezu sa Wi-Fi mrežom dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će privremeno prekinuti vezu sa Wi-Fi-jem dok je povezan sa uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Umetanje znaka"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje veliki broj SMS poruka. Želite li da dozvolite ovoj aplikaciji da nastavi sa slanjem poruka?"</string>
@@ -1842,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Ušteda baterije isključuje ili ograničava aktivnost u pozadini, neke vizuelne efekte i druge funkcije sa visokom potrošnjom da bi produžila trajanje baterije. "<annotation id="url">"Saznajte više"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Ušteda baterije isključuje ili ograničava aktivnost u pozadini, neke vizuelne efekte i druge funkcije sa visokom potrošnjom da bi produžila trajanje baterije."</string>
+    <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>
@@ -2087,4 +2039,23 @@
     </plurals>
     <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 4060ed7..92cad08 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Гукі будзільніка"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Гукі апавяшчэнняў"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Невядома"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">сетка Wi-Fi даступная</item>
-      <item quantity="few">сеткі Wi-Fi даступныя</item>
-      <item quantity="many">сетак Wi-Fi даступна</item>
-      <item quantity="other">сеткі Wi-Fi даступна</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">адкрытая сетка Wi-Fi даступная</item>
-      <item quantity="few">адкрытыя сеткі Wi-Fi даступныя</item>
-      <item quantity="many">адкрытых сетак Wi-Fi даступна</item>
-      <item quantity="other">адкрытай сеткі Wi-Fi даступна</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Падключыцеся да адкрытай сеткі Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Падключэнне да сеткі Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Выканана падключэнне да адкрытай сеткі Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не атрымалася падключыцца да адкрытай сеткі Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Дакраніцеся, каб убачыць усе сеткі"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Падключыцца"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Усе сеткі"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Дазволіць падключэнне да прапанаваных сетак Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Праграма \"<xliff:g id="NAME">%s</xliff:g>\" прапанавала сеткі. Прылада можа падключыцца да ніх аўтаматычна."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Дазволіць"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Не, дзякуй"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi уключыцца аўтаматычна"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Побач з захаванай сеткай з высакаякасным сігналам"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не ўключаць зноў"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi уключыўся аўтаматычна"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Вы знаходзіцеся побач з захаванай сеткай: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Уваход у сетку Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Увайдзіце ў сетку"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Падключана"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> мае абмежаваную магчымасць падключэння"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Націсніце, каб падключыцца"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Змяненні ў наладах хот-спота"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Частата хот-спота змянілася."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Прылада не можа працаваць толькі на частаце 5 ГГц. Гэта частата будзе выкарыстоўвацца, калі гэта магчыма."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Выкананы пераход да <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Прылада выкарыстоўвае сетку <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, калі ў сетцы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма доступу да інтэрнэту. Можа спаганяцца плата."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Выкананы пераход з <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> да <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невядомы тып сеткі"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" дрэннае падключэнне да Інтэрнэту."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Праграма %1$s хоча падключыцца да сеткі Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Праграма"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або хот-спот Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Дакраніцеся, каб убачыць налады"</string>
     <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
     <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Запрашэнне далучыцца"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Ад:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Тэлефон будзе часова адключаны ад сеткі Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Прылада Android TV будзе часова адключана ад сеткі Wi-Fi, пакуль яна падключана да прылады \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\""</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Тэлефон будзе часова адключаны ад Wi-Fi, пакуль ён падлучаны да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Прыкладанне &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; дасылае вялікую колькасць SMS-паведамленняў. Дазволіць гэтаму прыкладанню працягваць адпраўляць паведамленні?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі з высокімі энергавыдаткамі. "<annotation id="url">"Даведацца больш"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Каб павялічыць тэрмін службы акумулятара, рэжым эканоміі зараду выключае ці абмяжоўвае дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты і іншыя функцыі з высокімі энергавыдаткамі."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 b0cea11..9a4ca0c 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци на будилника"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци на известията"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Няма информация"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Има достъпни Wi-Fi мрежи</item>
-      <item quantity="one">Има достъпна Wi-Fi мрежа</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Има достъпни отворени Wi-Fi мрежи</item>
-      <item quantity="one">Има достъпна отворена Wi-Fi мрежа</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Свързване с отворена Wi‑Fi мрежа"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Установява се връзка с Wi-Fi мрежата"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Установихте връзка с Wi-Fi мрежата"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не можа да се установи връзка с Wi‑Fi мрежата"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Докоснете, за да видите всички мрежи"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Свързване"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Всички мрежи"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Да се разрешат ли предложените Wi‑Fi мрежи?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Предложени от <xliff:g id="NAME">%s</xliff:g> мрежи. Устройството може да се свърже автоматично."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Разрешаване"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Не, благодаря"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi ще се включи автоматично"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Когато сте в района на запазена мрежа с високо качество"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Без повторно включване"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi се включи автоматично"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Намирате се в района на запазена мрежа: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Влизане в Wi-Fi мрежа"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Вход в мрежата"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Установена е връзка"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена свързаност"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Докоснете, за да се свържете въпреки това"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промени в настройките ви за точка за достъп"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Честотната лента на точката ви за достъп е променена."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Това устройство не поддържа предпочитанието ви за използване само на честотната лента от 5 ГХц. Вместо това то ще я ползва, когато е възможно."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Превключи се към <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Устройството използва <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, когато <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> няма достъп до интернет. Възможно е да бъдете таксувани."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Превключи се от <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> към <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"виртуална частна мрежа (VPN)"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестен тип мрежа"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лоша връзка с интернет."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Да се разреши ли връзката?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложението %1$s иска да се свърже с Wi-Fi мрежата „%2$s“"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct не можа да се стартира."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Докоснете за настройки"</string>
     <string name="accept" msgid="1645267259272829559">"Приемам"</string>
     <string name="decline" msgid="2112225451706137894">"Отхвърлям"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Поканата е изпратена"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Покана за свързване"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"От:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"До:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблетът временно ще прекъсне връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Wi-Fi връзката на устройството ви с Android TV временно ще бъде прекратена, докато то е свързано към <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефонът временно ще прекрати връзката с Wi-Fi, докато е свързан с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; изпраща голям брой SMS съобщения. Искате ли да разрешите на това приложение да продължи да го прави?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Режимът за запазване на батерията изключва или ограничава активността на заден план, някои визуални ефекти и други функции с висок разход на енергия, за да удължи живота на батерията. "<annotation id="url">"Научете повече"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Режимът за запазване на батерията изключва или ограничава активността на заден план, някои визуални ефекти и други функции с висок разход на енергия, за да удължи живота на батерията."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 514a6ce..4dc5f5c 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"অ্যালার্মের শব্দ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"বিজ্ঞপ্তির শব্দ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"অজানা"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
-      <item quantity="other">ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
-      <item quantity="other">খোলা ওয়াই-ফাই নেটওয়ার্কগুলি উপলব্ধ রয়েছে</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"উন্মুক্ত ওয়াই-ফাই নেটওয়ার্কে সংযোগ করুন"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ওয়াই-ফাই নেটওয়ার্কে কানেক্ট করা হচ্ছে"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"উন্মুক্ত ওয়াই-ফাই নেটওয়ার্কে সংযুক্ত করা হয়েছে"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ওয়াই-ফাই নেটওয়ার্কে সংযোগ করা গেল না"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"সমস্ত নেটওয়ার্ক দেখতে ট্যাপ করুন"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"সংযুক্ত করুন"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"সব নেটওয়ার্ক"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"সাজেস্ট করা ওয়াই-ফাই নেটওয়ার্কে কানেক্ট করার অনুমতি দিতে চান?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g>-এর সাজেস্ট করা নেটওয়ার্ক। ডিভাইস নিজে থেকে কানেক্ট হতে পারে।"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"অনুমতি দিন"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"না থাক"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ওয়াই-ফাই অটোমেটিক চালু হবে"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"যখন আপনি একটি উচ্চ মানের সংরক্ষিত নেটওয়ার্ক কাছাকাছি থাকেন"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"আবার চালু করবেন না"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ওয়াই-ফাই নিজে থেকে চালু করা হয়েছে"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"আপনি একটি সেভ করা নেটওয়ার্কের কাছেই আছেন: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ওয়াই-ফাই নেটওয়ার্কে সাইন-ইন করুন"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"নেটওয়ার্কে সাইন-ইন করুন"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"কানেক্ট করা হয়েছে"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-এর সীমিত কানেক্টিভিটি আছে"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"তবুও কানেক্ট করতে ট্যাপ করুন"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"আপনার হটস্পট সেটিংসে পরিবর্তনগুলি"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"আপনার হটস্পট ব্যান্ড পরিবর্তন করা হয়েছে।"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"এই ডিভাইসটি শুধুমাত্র 5GHz এর জন্য আপনার পছন্দ সমর্থন করে না। পরিবর্তে, এই ডিভাইসটি 5GHz ব্যান্ড ব্যবহার করবে।"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> এ পাল্টানো হয়েছে"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> এ ইন্টারনেট অ্যাক্সেস না থাকলে <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ব্যবহার করা হয়৷ ডেটা চার্জ প্রযোজ্য৷"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> থেকে <xliff:g id="NEW_NETWORK">%2$s</xliff:g> এ পাল্টানো হয়েছে"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"এই নেটওয়ার্কের প্রকার অজানা"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ওয়াই-ফাই এর সাথে সংযোগ করা যায়নি"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"সংযোগের অনুমতি দেবেন?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"অ্যাপ্লিকেশান %1$s ওয়াই ফাই নেটওয়ার্ক %2$s এর সাথে সংযোগ করতে চায়"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"একটি অ্যাপ্লিকেশান"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ওয়াই-ফাই ডাইরেক্ট"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ওয়াই-ফাই ডাইরেক্ট আরম্ভ করুন৷ এটি ওয়াই-ফাই client/hotspot কে বন্ধ করবে৷"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ওয়াই-ফাই ডাইরেক্ট শুরু করা যায়নি৷"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ওয়াই-ফাই ডাইরেক্ট চালু রয়েছে"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"সেটিংসের জন্য আলতো চাপুন"</string>
     <string name="accept" msgid="1645267259272829559">"গ্রহণ করুন"</string>
     <string name="decline" msgid="2112225451706137894">"অস্বীকার করুন"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"আমন্ত্রণ পাঠানো হয়েছে"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"সংযুক্ত হওয়ার আমন্ত্রণ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"থেকে:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"প্রাপক:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"প্রয়োজনীয় পিনটি লিখুন:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"পিন:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ট্যাবলেটটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-এ কানেক্ট থাকা অবস্থায় আপনার Android TV ডিভাইস সাময়িকভাবে ওয়াই-ফাই থেকে ডিসকানেক্ট হয়ে যাবে"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ফোনটি যখন <xliff:g id="DEVICE_NAME">%1$s</xliff:g> এ সংযুক্ত হবে তখন এটি ওয়াই-ফাই থেকে সাময়িকভাবে সংযোগ বিচ্ছিন্ন হবে"</string>
     <string name="select_character" msgid="3365550120617701745">"অক্ষর ঢোকান"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"এসএমএস পাঠানো হচ্ছে"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; অনেকগুলি এসএমএস পাঠাচ্ছে৷ আপনি কি এই অ্যাপ্লিকেশানটিকে মেসেজ পাঠানো চালিয়ে যাওয়ার অনুমতি দিতে চান?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে। "<annotation id="url">"আরও জানুন"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ব্যাটারি আরও বেশিক্ষণ চালাতে ব্যাটারি সেভার ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজুয়াল এফেক্ট ও অতিরিক্ত শক্তি খরচ হয় এমন অন্যান্য ফিচার বন্ধ বা সীমাবদ্ধ করে।"</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 1ddc0e2..ea4d209 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1266,32 +1266,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvukovi alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvukovi obavještenja"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">WiFi mreže su dostupne</item>
-      <item quantity="few">WiFi mreže su dostupne</item>
-      <item quantity="other">WiFi mreže su dostupne</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Otvorene WiFi mreže su dostupne</item>
-      <item quantity="few">Otvorene WiFi mreže su dostupne</item>
-      <item quantity="other">Otvorene WiFi mreže su dostupne</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Povežite se na otvorenu Wi‑Fi mrežu"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Povezivanje na WiFi mrežu"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Povezani ste na Wi‑Fi mrežu"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nije se moguće povezati na Wi‑Fi mrežu"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Dodirnite da vidite sve mreže"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Povežite se"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Sve mreže"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Dozvoliti predložene WiFi mreže?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Mreže koje predlaže <xliff:g id="NAME">%s</xliff:g>. Uređaj će se možda povezati automatski."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Dozvoli"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, hvala"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"WiFi će se uključiti automatski"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kada ste u blizini sačuvane mreže visokog kvaliteta"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Nemoj ponovo uključiti"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi veza se automatski uključila"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"U blizini ste sačuvane mreže: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavljivanje na WiFi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1304,9 +1278,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Mreža <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da se ipak povežete"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promjene postavki vaše pristupne tačke"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Opseg vaše pristupne tačke je promijenjen."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava vašu postavku za mreže od isključivo 5GHz. Uređaj će koristiti opseg of 5GHz kada je dostupan."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Prebačeno na: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, uređaj koristi mrežu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata usluge."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prebačeno iz mreže <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> u <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mrežu"</string>
@@ -1318,27 +1289,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na WiFi mrežu"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internetsku vezu."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s se želi povezati na WiFi mrežu %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni WiFi Direct. To će isključiti WiFi klijenta/pristupnu tačku."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Greška u pokretanju opcije WiFi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct je uključen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dodirnite za postavke"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
     <string name="decline" msgid="2112225451706137894">"Odbijte"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica poslana"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozivnica za povezivanje"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Unesite potrebni PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će privremeno prekinuti WiFi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Povezanost Android TV uređaja i WiFi mreže će se privremeno prekinuti dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će privremeno prekinuti WiFi vezu dok bude povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Umetni karakter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje veliki broj SMS poruka. Da li želite dozvoliti ovoj aplikaciji da nastavi slanje poruka?"</string>
@@ -1844,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"U cilju produženja trajanja baterije, funkcija Ušteda baterije isključuje ili ograničava aktivnost u pozadini, neke vizuelne efekte i druge funkcije koje troše puno energije. "<annotation id="url">"Saznajte više"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"U cilju produženja trajanja baterije, funkcija Ušteda baterije isključuje ili ograničava aktivnost u pozadini, neke vizuelne efekte i druge funkcije koje troše puno energije."</string>
+    <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>
@@ -2089,4 +2041,23 @@
     </plurals>
     <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 fe7f87c..4f9eeb8 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de l\'alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificació"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconegut"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Xarxes Wi-Fi disponibles</item>
-      <item quantity="one">Xarxa Wi-Fi disponible</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Xarxes Wi-Fi obertes disponibles</item>
-      <item quantity="one">Xarxa Wi-Fi oberta disponible</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connecta\'t a una xarxa Wi-Fi oberta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"S\'està connectant a una xarxa Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"S\'ha connectat a la xarxa Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"No s\'ha pogut connectar a una xarxa Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toca per veure totes les xarxes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connecta"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Totes les xarxes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vols permetre les xarxes Wi‑Fi suggerides?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Xarxes suggerides de l\'aplicació <xliff:g id="NAME">%s</xliff:g>. El dispositiu pot connectar-se automàticament."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permet"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, gràcies"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"La Wi-Fi s\'activarà automàticament"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quan siguis a prop d\'una xarxa de qualitat desada"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"No tornis a activar"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"La Wi‑Fi s\'ha activat automàticament"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ets a prop d\'una xarxa desada: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia la sessió a la xarxa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inicia la sessió a la xarxa"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connectat"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> té una connectivitat limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca per connectar igualment"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Canvis en la configuració del punt d\'accés Wi-Fi"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ha canviat la teva banda del punt d\'accés Wi-Fi."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Aquest dispositiu no admet utilitzar exclusivament una banda de 5 GHz. El dispositiu utilitzarà una banda de 5 GHz quan estigui disponible."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Actualment en ús: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositiu utilitza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> en cas que <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tingui accés a Internet. És possible que s\'hi apliquin càrrecs."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Abans es feia servir la xarxa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>; ara s\'utilitza <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"una tipus de xarxa desconegut"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" té una mala connexió a Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vols permetre la connexió?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'aplicació %1$s vol connectar-se a la xarxa Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicació"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/el punt d\'accés Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No s\'ha pogut iniciar Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toca per veure la configuració"</string>
     <string name="accept" msgid="1645267259272829559">"Accepta"</string>
     <string name="decline" msgid="2112225451706137894">"Rebutja"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"S\'ha enviat la invitació"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitació per connectar"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Per a:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tauleta es desconnectarà temporalment de la Wi-Fi mentre estigui connectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"El dispositiu Android TV es desconnectarà temporalment de la Wi‑Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El telèfon es desconnectarà temporalment de la Wi-Fi mentre estigui connectat a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; està enviant molts missatges SMS. Vols permetre que aquesta aplicació continuï enviant missatges?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Per tal de prolongar la durada de la bateria, el mode Estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia. "<annotation id="url">"Més informació"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Per tal de prolongar la durada de la bateria, el mode Estalvi de bateria desactiva o restringeix les activitats en segon pla, alguns efectes visuals i altres funcions que consumeixen molta energia."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 b684193..502a7a8 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíku"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornění"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Neznámé"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="few">K dispozici jsou sítě Wi-Fi</item>
-      <item quantity="many">K dispozici jsou sítě Wi-Fi</item>
-      <item quantity="other">K dispozici jsou sítě Wi-Fi</item>
-      <item quantity="one">K dispozici je síť Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="few">K dispozici jsou veřejné sítě Wi-Fi</item>
-      <item quantity="many">K dispozici jsou veřejné sítě Wi-Fi</item>
-      <item quantity="other">K dispozici jsou veřejné sítě Wi-Fi</item>
-      <item quantity="one">K dispozici je veřejná síť Wi-Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Připojení k otevřené síti Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Připojování k síti Wi-Fi..."</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Připojeno k síti Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Připojení k síti Wi-Fi se nezdařilo"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Klepnutím zobrazíte všechny sítě"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Připojit"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Všechny sítě"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Povolit navrhované sítě Wi-Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Sítě navrhované aplikací <xliff:g id="NAME">%s</xliff:g>. Zařízení se může připojovat automaticky."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Povolit"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, díky"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi se zapne automaticky"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Když budete v dosahu kvalitní uložené sítě"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Znovu nezapínat"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Automaticky se zapnulo připojení Wi-Fi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Jste v dosahu uložené sítě: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Přihlásit se k síti Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Přihlásit se k síti"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Připojeno"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Síť <xliff:g id="NETWORK_SSID">%1$s</xliff:g> umožňuje jen omezené připojení"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Klepnutím se i přesto připojíte"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Změny nastavení hotspotu"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pásmo hotspotu se změnilo."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Toto zařízení nepodporuje vaše nastavení jen 5GHz pásma. Zařízení použije pásmo 5 GHz, jen když bude dostupné."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Přechod na síť <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Když síť <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nebude mít přístup k internetu, zařízení použije síť <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Mohou být účtovány poplatky."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Přechod ze sítě <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na síť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámý typ sítě"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má pomalé připojení k internetu."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povolit připojení?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikace %1$s se chce připojit k síti Wi-Fi %2$s."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikace"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit Wi-Fi Direct. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct se nepodařilo spustit."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je zapnuto"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Klepnutím přejdete do nastavení"</string>
     <string name="accept" msgid="1645267259272829559">"Přijmout"</string>
     <string name="decline" msgid="2112225451706137894">"Odmítnout"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka odeslána."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozvánka k připojení"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Zatímco bude zařízení Android TV připojeno k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, dočasně se odpojí od sítě Wi-Fi."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon se při připojení k zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasně odpojí od sítě Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikace &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;odesílá velký počet SMS zpráv. Chcete aplikaci povolit, aby zprávy odesílala i nadále?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Spořič baterie vypíná nebo omezuje aktivitu na pozadí, některé vizuální efekty a další funkce náročné na energii, aby vám pomohl šetřit baterii. "<annotation id="url">"Další informace"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Spořič baterie vypíná nebo omezuje aktivitu na pozadí, některé vizuální efekty a další funkce náročné na energii, aby vám pomohl šetřit baterii."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 22f1e5d..d347e35 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyde"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notifikationslyde"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ukendt"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Tilgængelige Wi-Fi-netværk</item>
-      <item quantity="other">Tilgængelige Wi-Fi-netværk</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Åbne Wi-Fi-netværk er tilgængelige</item>
-      <item quantity="other">Åbne Wi-Fi-netværk er tilgængelige</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Opret forbindelse til et åbent Wi-Fi-netværk"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Opretter forbindelse til Wi-Fi-netværket"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Forbundet til Wi-Fi-netværket"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Der kan ikke oprettes forbindelse til Wi-Fi-netværket"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tryk for at se alle netværk"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Opret forbindelse"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alle netværk"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vil du tillade foreslåede Wi‑Fi-netværk?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Netværk foreslået af <xliff:g id="NAME">%s</xliff:g>. Enheden opretter muligvis forbindelse automatisk."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Tillad"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nej tak"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi aktiveres automatisk"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Når du er i nærheden af et gemt netværk af høj kvalitet"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Aktivér ikke igen"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi blev automatisk aktiveret"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Du er i nærheden af et gemt netværk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log ind på Wi-Fi-netværk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Log ind på netværk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Der er oprettet forbindelse"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrænset forbindelse"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tryk for at oprette forbindelse alligevel"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ændringer af dine indstillinger for hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Dit hotspotbånd er ændret."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Denne enhed understøtter ikke din præference om kun 5 GHz. Denne enhed vil i stedet bruge 5 GHz-båndet, når det er muligt."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Der blev skiftet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Enheden benytter <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, når der ikke er internetadgang via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Der opkræves muligvis betaling."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Der blev skiftet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukendt netværkstype"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig internetforbindelse."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillade denne forbindelse?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Applikationen %1$s vil gerne have forbindelse til Wi-Fi-netværk %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En applikation"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct kunne ikke startes."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tryk for at se indstillinger"</string>
     <string name="accept" msgid="1645267259272829559">"Accepter"</string>
     <string name="decline" msgid="2112225451706137894">"Afvis"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitationen er sendt"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation til forbindelse"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Fra:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Wi-Fi-forbindelse til tabletten vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Wi-Fi-forbindelsen til din Android TV-enhed bliver midlertidigt afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonens Wi-Fi-forbindelse vil midlertidigt blive afbrudt, når den er tilsluttet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sender et stort antal sms-beskeder. Vil du tillade, at denne app fortsat sender beskeder?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Batterisparefunktion deaktiverer eller begrænser baggrundsaktivitet, visse visuelle effekter og andre batterikrævende funktioner for at forlænge batteritiden. "<annotation id="url">"Få flere oplysninger"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Batterisparefunktion deaktiverer eller begrænser baggrundsaktivitet, visse visuelle effekter og andre batterikrævende funktioner for at forlænge batteritiden."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 b74cd7e..b4b40ea 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Weckertöne"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Benachrichtigungstöne"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Unbekannt"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">WLANs verfügbar</item>
-      <item quantity="one">WLAN verfügbar</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Verfügbare WLANs öffnen</item>
-      <item quantity="one">Verfügbares WLAN öffnen</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Mit offenem WLAN verbinden"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Verbindung zu WLAN wird hergestellt"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Mit WLAN verbunden"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"WLAN-Verbindung konnte nicht hergestellt werden"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tippen, um alle Netzwerke zu sehen"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Verbinden"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alle Netzwerke"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vorgeschlagene WLANs zulassen?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Von <xliff:g id="NAME">%s</xliff:g> vorgeschlagene Netzwerke. Gerät verbindet sich möglicherweise automatisch."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Zulassen"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nein danke"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"WLAN wird automatisch aktiviert"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Wenn du in der Nähe eines sicheren gespeicherten Netzwerks bist"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Nicht wieder aktivieren"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"WLAN automatisch aktiviert"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Du bist in der Nähe eines gespeicherten Netzwerks: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"In WLAN anmelden"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Im Netzwerk anmelden"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Verbunden"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Schlechte Verbindung mit <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tippen, um die Verbindung trotzdem herzustellen"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Änderungen an deinen Hotspot-Einstellungen"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Dein Hotspot-Band hat sich geändert."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dieses Gerät unterstützt die ausschließliche Nutzung von 5 GHz nicht. Es greift aber immer auf das 5-GHz-Band zurück, wenn dieses verfügbar ist."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Zu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> gewechselt"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Auf dem Gerät werden <xliff:g id="NEW_NETWORK">%1$s</xliff:g> genutzt, wenn über <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> kein Internet verfügbar ist. Eventuell fallen Gebühren an."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Von \"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>\" zu \"<xliff:g id="NEW_NETWORK">%2$s</xliff:g>\" gewechselt"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ein unbekannter Netzwerktyp"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" hat eine schlechte Internetverbindung."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbindung zulassen?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Die App \"%1$s\" möchte eine Verbindung zum WLAN %2$s herstellen."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Eine App"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Starten von Wi-Fi Direct nicht möglich"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Für Einstellungen tippen"</string>
     <string name="accept" msgid="1645267259272829559">"Akzeptieren"</string>
     <string name="decline" msgid="2112225451706137894">"Ablehnen"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Einladung gesendet"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Einladung zum Aufbau einer Verbindung"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Von:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"An:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gib die PIN ein:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Das Tablet wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> besteht."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Das Android TV-Gerät wird vorübergehend vom WLAN getrennt, während es mit \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\" verbunden ist."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Das Telefon wird vorübergehend vom WLAN getrennt, während eine Verbindung mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> hergestellt wird."</string>
     <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS werden gesendet"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sendet eine große Anzahl SMS. Möchtest du zulassen, dass die App weiterhin Nachrichten sendet?"</string>
@@ -1817,8 +1771,10 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Von deinem Administrator aktualisiert"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Von deinem Administrator gelöscht"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Ok"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Im Energiesparmodus werden Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen mit hohem Energiebedarf abgeschaltet oder eingeschränkt, um die Akkulaufzeit zu verlängern. "<annotation id="url">"Weitere Informationen"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Im Energiesparmodus werden Hintergrundaktivitäten, einige optische Effekte und weitere Funktionen mit hohem Energiebedarf abgeschaltet oder eingeschränkt, um die Akkulaufzeit zu verlängern."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <string name="data_saver_description" msgid="6015391409098303235">"Der Datensparmodus verhindert zum einen, dass Apps im Hintergrund Daten senden oder empfangen, sodass weniger Daten verbraucht werden. Zum anderen werden die Datenzugriffe der gerade aktiven App eingeschränkt, was z. B. dazu führen kann, dass Bilder erst angetippt werden müssen, bevor sie sichtbar werden."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Datensparmodus aktivieren?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivieren"</string>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 e74cbb1..73828a1 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ήχοι ξυπνητηριού"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ήχοι ειδοποίησης"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Άγνωστο"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Υπάρχουν διαθέσιμα δίκτυα Wi-Fi</item>
-      <item quantity="one">Υπάρχει διαθέσιμο δίκτυο Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Υπάρχουν διαθέσιμα ανοικτά δίκτυα Wi-Fi</item>
-      <item quantity="one">Υπάρχει διαθέσιμο ανοικτό δίκτυο Wi-Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Σύνδεση σε ανοιχτό δίκτυο Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Σύνδεση σε δίκτυο Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ολοκληρώθηκε η σύνδεση στο δίκτυο Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Δεν ήταν δυνατή η σύνδεση σε δίκτυο Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Πατήστε για να δείτε όλα τα δίκτυα"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Σύνδεση"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Όλα τα δίκτυα"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Να επιτρέπονται προτεινόμενα δίκτυα Wi‑Fi;"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Προτεινόμενα δίκτυα <xliff:g id="NAME">%s</xliff:g>. Η συσκευή μπορεί να συνδεθεί αυτόματα."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Αποδοχή"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Όχι, ευχαριστώ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Το Wi‑Fi θα ενεργοποιηθεί αυτόματα"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Όταν βρίσκεστε κοντά σε αποθηκευμένο δίκτυο υψηλής ποιότητας"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Να μην ενεργοποιηθεί ξανά"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Το Wi‑Fi ενεργοποιήθηκε αυτόματα"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Βρίσκεστε κοντά σε αποθηκευμένο δίκτυο: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Συνδεθείτε στο δίκτυο Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Σύνδεση στο δίκτυο"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Συνδέθηκε"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Το δίκτυο <xliff:g id="NETWORK_SSID">%1$s</xliff:g> έχει περιορισμένη συνδεσιμότητα"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Πατήστε για σύνδεση ούτως ή άλλως"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Αλλαγές στις ρυθμίσεις σημείου πρόσβασης Wi-Fi"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Το εύρος σημείου πρόσβασης Wi-Fi άλλαξε."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Αυτή η συσκευή δεν υποστηρίζει την προτίμησή σας για τη ζώνη 5 GHz μόνο. Αντ\' αυτού, αυτή η συσκευή θα χρησιμοποιεί τη ζώνη 5 GHz όταν είναι διαθέσιμη."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Μετάβαση σε δίκτυο <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Η συσκευή χρησιμοποιεί το δίκτυο <xliff:g id="NEW_NETWORK">%1$s</xliff:g> όταν το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> δεν έχει πρόσβαση στο διαδίκτυο. Μπορεί να ισχύουν χρεώσεις."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Μετάβαση από το δίκτυο <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> στο δίκτυο <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"άγνωστος τύπος δικτύου"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" έχει κακή σύνδεση Διαδικτύου."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Να επιτρέπεται η σύνδεση;"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Η εφαρμογή %1$s θα ήθελε να συνδεθεί με το δίκτυο WiFi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Μια εφαρμογή"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Δεν ήταν δυνατή η εκκίνηση του Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Πατήστε για να μεταβείτε στις ρυθμίσεις"</string>
     <string name="accept" msgid="1645267259272829559">"Αποδοχή"</string>
     <string name="decline" msgid="2112225451706137894">"Απόρριψη"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Η πρόσκληση στάλθηκε"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Πρόσκληση για σύνδεση"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Από:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Προς:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Το tablet θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Η συσκευή σας Android TV θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi, ενόσω είναι συνδεδεμένη στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Το τηλέφωνο θα αποσυνδεθεί προσωρινά από το δίκτυο Wi-Fi ενώ συνδέεται στη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Η εφαρμογή &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; στέλνει έναν μεγάλο αριθμό μηνυμάτων SMS. Θέλετε να επιτρέψετε σε αυτήν την εφαρμογή να συνεχίσει να στέλνει μηνύματα;"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Η Εξοικονόμηση μπαταρίας απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες υψηλής κατανάλωσης ενέργειας για την επέκταση της διάρκειας ζωής μπαταρίας. "<annotation id="url">"Μάθετε περισσότερα"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Η Εξοικονόμηση μπαταρίας απενεργοποιεί ή περιορίζει τη δραστηριότητα παρασκηνίου, ορισμένα οπτικά εφέ και άλλες λειτουργίες υψηλής κατανάλωσης ενέργειας για την επέκταση της διάρκειας ζωής μπαταρίας."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 88fb0fd..9163214 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi networks available</item>
-      <item quantity="one">Wi-Fi network available</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Open Wi-Fi networks available</item>
-      <item quantity="one">Open Wi-Fi network available</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connect to open Wi‑Fi network"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connecting to Wi‑Fi network"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connected to Wi‑Fi network"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Could not connect to Wi‑Fi network"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tap to see all networks"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connect"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"All networks"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Allow suggested Wi‑Fi networks?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> suggested networks. Device may connect automatically."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Allow"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, thanks"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi will turn on automatically"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"When you\'re near a high‑quality saved network"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Don\'t turn back on"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi turned on automatically"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"You\'re near a saved network: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tap for settings"</string>
     <string name="accept" msgid="1645267259272829559">"Accept"</string>
     <string name="decline" msgid="2112225451706137894">"Decline"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation to connect"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"From:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
@@ -1817,8 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life. "<annotation id="url">"Learn more"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 8a1c2c4..dff558f 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi networks available</item>
-      <item quantity="one">Wi-Fi network available</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Open Wi-Fi networks available</item>
-      <item quantity="one">Open Wi-Fi network available</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connect to open Wi‑Fi network"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connecting to Wi‑Fi network"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connected to Wi‑Fi network"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Could not connect to Wi‑Fi network"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tap to see all networks"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connect"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"All networks"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Allow suggested Wi‑Fi networks?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> suggested networks. Device may connect automatically."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Allow"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, thanks"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi will turn on automatically"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"When you\'re near a high‑quality saved network"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Don\'t turn back on"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi turned on automatically"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"You\'re near a saved network: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tap for settings"</string>
     <string name="accept" msgid="1645267259272829559">"Accept"</string>
     <string name="decline" msgid="2112225451706137894">"Decline"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation to connect"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"From:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
@@ -1817,8 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life. "<annotation id="url">"Learn more"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 88fb0fd..9163214 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi networks available</item>
-      <item quantity="one">Wi-Fi network available</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Open Wi-Fi networks available</item>
-      <item quantity="one">Open Wi-Fi network available</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connect to open Wi‑Fi network"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connecting to Wi‑Fi network"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connected to Wi‑Fi network"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Could not connect to Wi‑Fi network"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tap to see all networks"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connect"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"All networks"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Allow suggested Wi‑Fi networks?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> suggested networks. Device may connect automatically."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Allow"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, thanks"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi will turn on automatically"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"When you\'re near a high‑quality saved network"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Don\'t turn back on"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi turned on automatically"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"You\'re near a saved network: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tap for settings"</string>
     <string name="accept" msgid="1645267259272829559">"Accept"</string>
     <string name="decline" msgid="2112225451706137894">"Decline"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation to connect"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"From:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
@@ -1817,8 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life. "<annotation id="url">"Learn more"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 88fb0fd..9163214 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm Sounds"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification Sounds"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Unknown"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi networks available</item>
-      <item quantity="one">Wi-Fi network available</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Open Wi-Fi networks available</item>
-      <item quantity="one">Open Wi-Fi network available</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connect to open Wi‑Fi network"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connecting to Wi‑Fi network"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connected to Wi‑Fi network"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Could not connect to Wi‑Fi network"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tap to see all networks"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connect"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"All networks"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Allow suggested Wi‑Fi networks?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> suggested networks. Device may connect automatically."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Allow"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, thanks"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi will turn on automatically"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"When you\'re near a high‑quality saved network"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Don\'t turn back on"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi turned on automatically"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"You\'re near a saved network: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Sign in to a Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Sign in to network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connected"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> has limited connectivity"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tap to connect anyway"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Changes to your hotspot settings"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Your hotspot band has changed."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"This device doesn’t support your preference for 5 GHz only. Instead, this device will use the 5 GHz band when available."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Switched to <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Device uses <xliff:g id="NEW_NETWORK">%1$s</xliff:g> when <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> has no Internet access. Charges may apply."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Switched from <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> to <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"an unknown network type"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" has a poor Internet connection."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Allow connection?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Application %1$s would like to connect to Wi-Fi Network %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"An application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tap for settings"</string>
     <string name="accept" msgid="1645267259272829559">"Accept"</string>
     <string name="decline" msgid="2112225451706137894">"Decline"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation to connect"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"From:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"The tablet will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"The phone will temporarily disconnect from Wi-Fi while it\'s connected to <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Insert character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?"</string>
@@ -1817,8 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Updated by your admin"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"OK"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life. "<annotation id="url">"Learn more"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life."</string>
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”\n\n"<annotation id="url">"Learn more"</annotation></string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"To extend battery life, Battery Saver:\n·Turns on Dark theme\n·Turns off or restricts background activity, some visual effects and other features like “Hey Google”"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app that you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Turn on Data Saver?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Turn on"</string>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 fbb1cc7..7519ad6 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎Alarm sounds‎‏‎‎‏‎"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‎‎‎‏‎‎Notification sounds‎‏‎‎‏‎"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎Unknown‎‏‎‎‏‎"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎Wi-Fi networks available‎‏‎‎‏‎</item>
-      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‏‎‎Wi-Fi network available‎‏‎‎‏‎</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎Open Wi-Fi networks available‎‏‎‎‏‎</item>
-      <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‎‎‏‏‏‏‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‎‎Open Wi-Fi network available‎‏‎‎‏‎</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎Connect to open Wi‑Fi network‎‏‎‎‏‎"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‎‏‎‎Connecting to Wi‑Fi network‎‏‎‎‏‎"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‎‎Connected to Wi‑Fi network‎‏‎‎‏‎"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‏‎‎‎Could not connect to Wi‑Fi network‎‏‎‎‏‎"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‏‎‏‎‏‎‏‎Tap to see all networks‎‏‎‎‏‎"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎Connect‎‏‎‎‏‎"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎All networks‎‏‎‎‏‎"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‎‎‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎‎‏‎Allow suggested Wi‑Fi networks?‎‏‎‎‏‎"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="NAME">%s</xliff:g>‎‏‎‎‏‏‏‎ suggested networks. Device may connect automatically.‎‏‎‎‏‎"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‏‎Allow‎‏‎‎‏‎"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎No thanks‎‏‎‎‏‎"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‏‎‎‎Wi‑Fi will turn on automatically‎‏‎‎‏‎"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‏‏‏‎‎‏‏‏‎‏‎When you\'re near a high quality saved network‎‏‎‎‏‎"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎Don\'t turn back on‎‏‎‎‏‎"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎Wi‑Fi turned on automatically‎‏‎‎‏‎"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‏‎‏‎‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎You\'re near a saved network: ‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎Sign in to Wi-Fi network‎‏‎‎‏‎"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎Sign in to network‎‏‎‎‏‎"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎Connected‎‏‎‎‏‎"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="NETWORK_SSID">%1$s</xliff:g>‎‏‎‎‏‏‏‎ has limited connectivity‎‏‎‎‏‎"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎Tap to connect anyway‎‏‎‎‏‎"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎Changes to your hotspot settings‎‏‎‎‏‎"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎Your hotspot band has changed.‎‏‎‎‏‎"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‏‎‎‎‏‎This device doesn’t support your preference for 5GHz only. Instead, this device will use the 5GHz band when available.‎‏‎‎‏‎"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‎‏‏‏‏‏‎Switched to ‎‏‎‎‏‏‎<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎Device uses ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ when ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎ has no internet access. Charges may apply.‎‏‎‎‏‎"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‎Switched from ‎‏‎‎‏‏‎<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to ‎‏‎‎‏‏‎<xliff:g id="NEW_NETWORK">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‎VPN‎‏‎‎‏‎"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‎‎‏‏‎‎‎‎‎an unknown network type‎‏‎‎‏‎"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎Couldn\'t connect to Wi-Fi‎‏‎‎‏‎"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎ has a poor internet connection.‎‏‎‎‏‎"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎Allow connection?‎‏‎‎‏‎"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎Application %1$s would like to connect to Wifi Network %2$s‎‏‎‎‏‎"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎An application‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎Wi-Fi Direct‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‎‎Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‎‏‎‎‎‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎Couldn\'t start Wi-Fi Direct.‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‎Wi-Fi Direct is on‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‎‏‏‏‎Tap for settings‎‏‎‎‏‎"</string>
     <string name="accept" msgid="1645267259272829559">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‏‎Accept‎‏‎‎‏‎"</string>
     <string name="decline" msgid="2112225451706137894">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎Decline‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‎Invitation sent‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎Invitation to connect‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎From:‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‎‎‎‏‏‎To:‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‏‏‎‎‎‎‎‏‏‏‎‎‎‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‎‎Type the required PIN:‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‎PIN:‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‏‎‏‏‎‏‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎The tablet will temporarily disconnect from Wi-Fi while it\'s connected to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‎‏‏‎‎Your Android TV device will temporarily disconnect from Wi-Fi while it\'s connected to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‏‎‏‏‏‏‏‎The phone will temporarily disconnect from Wi-Fi while it\'s connected to ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="select_character" msgid="3365550120617701745">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‎‎‏‎Insert character‎‏‎‎‏‎"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‎‏‎‏‎‏‎‏‎‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎Sending SMS messages‎‏‎‎‏‎"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎&lt;b&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/b&gt; is sending a large number of SMS messages. Do you want to allow this app to continue sending messages?‎‏‎‎‏‎"</string>
@@ -1817,8 +1771,8 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‎‎‏‎Updated by your admin‎‏‎‎‏‎"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Deleted by your admin‎‏‎‎‏‎"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‏‎OK‎‏‎‎‏‎"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life. ‎‏‎‎‏‏‎"<annotation id="url">"‎‏‎‎‏‏‏‎Learn More‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‎‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎Battery Saver turns off or restricts background activity, some visual effects &amp; other high-power features to extend battery life.‎‏‎‎‏‎"</string>
+    <string name="battery_saver_description_with_learn_more" msgid="1002571337088673987">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‎‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‎‎‎‏‏‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎·Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎·Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎"<annotation id="url">"‎‏‎‎‏‏‏‎Learn more‎‏‎‎‏‏‎"</annotation>"‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="battery_saver_description" msgid="2307555792915978653">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‏‏‎‎‏‏‏‎‏‎To extend battery life, Battery Saver:‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎·Turns on Dark theme‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎·Turns off or restricts background activity, some visual effects, and other features like “Hey Google”‎‏‎‎‏‎"</string>
     <string name="data_saver_description" msgid="6015391409098303235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‎‎‎‎‎‏‏‎To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.‎‏‎‎‏‎"</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‎‏‎Turn on Data Saver?‎‏‎‎‏‎"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎Turn on‎‏‎‎‏‎"</string>
@@ -2051,4 +2005,14 @@
     </plurals>
     <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 7fe219e..0381249 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">redes de Wi-Fi disponibles</item>
-      <item quantity="one">red de Wi-Fi disponible</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Abrir redes de Wi-Fi disponibles</item>
-      <item quantity="one">Abrir red de Wi-Fi disponible</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conectarse a una red Wi-Fi abierta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Estableciendo conexión con la red Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Se conectó a la red Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"No fue posible conectarse a la red Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Presiona para ver todas las redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectar"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas las redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"¿Quieres permitir las redes Wi‑Fi sugeridas?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> sugirió redes. Es posible que el dispositivo se conecte automáticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, gracias"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Se activará la conexión Wi-Fi automáticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Cuando estés cerca de una red guardada de alta calidad"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"No volver a activar"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Se activó el Wi-Fi automáticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Estás cerca de una red guardada: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accede a una red Wi-Fi."</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Acceder a la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Se estableció conexión"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene conectividad limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Presiona para conectarte de todas formas"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios en la configuración de tu hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Cambió la banda de tu hotspot."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Si bien este dispositivo no admite la opción para conectarse exclusivamente a bandas de 5 GHz, las usará cuando estén disponibles."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Se cambió a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se cambió de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de red desconocido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere conectarse a la red Wi-Fi %2$s."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi directo"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi directo. Se desactivará el funcionamiento del hotspot o del cliente Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se pudo iniciar Wi-Fi directo."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi directo."</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Presiona para ver la configuración"</string>
     <string name="accept" msgid="1645267259272829559">"Aceptar"</string>
     <string name="decline" msgid="2112225451706137894">"Rechazar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Se envió la invitación."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitación para conectarse"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tablet se desconectará temporalmente de la red Wi-Fi mientras esté conectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Se desconectará temporalmente el dispositivo Android TV de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El dispositivo se desconectará temporalmente de la red Wi-Fi mientras esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está enviando una gran cantidad de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"El Ahorro de batería desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones que consumen mucha energía a fin de extender la duración de batería. "<annotation id="url">"Más información"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"El Ahorro de batería desactiva o restringe la actividad en segundo plano, algunos efectos visuales y otras funciones que consumen mucha energía para extender la duración de la batería."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 35e2c38..7f152e1 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sonidos de la alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sonidos de notificaciones"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconocido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Redes Wi-Fi disponibles</item>
-      <item quantity="one">Red Wi-Fi disponible</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Redes Wi-Fi abiertas disponibles</item>
-      <item quantity="one">Red Wi-Fi abierta disponible</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conectarse a una red Wi-Fi abierta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Estableciendo conexión con la red Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Conectado a la red Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"No se ha podido conectar a la red Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toca para ver todas las redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectarse"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas las redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"¿Permitir sugerencias de redes Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> te ha sugerido alguna red. El dispositivo puede que se conecte automáticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, gracias"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"La conexión Wi‑Fi se activará automáticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Cuando estés cerca de una red de alta calidad guardada"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"No volver a activar"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi activada automáticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Estás cerca de una red guardada: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sesión en red Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Iniciar sesión en la red"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tiene una conectividad limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca para conectarte de todas formas"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios en los ajustes de tu punto de acceso"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La banda de tu punto de acceso ha cambiado."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo no admite la opción de conectarse exclusivamente a bandas de 5 GHz, pero las usará cuando estén disponibles."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Se ha cambiado a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"El dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cuando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> no tiene acceso a Internet. Es posible que se apliquen cargos."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Se ha cambiado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo de red desconocido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tiene una mala conexión a Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"¿Permitir la conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"La aplicación %1$s quiere establecer conexión con la red Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Una aplicación"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento del punto de acceso o cliente Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se ha podido iniciar Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toca para ver ajustes"</string>
     <string name="accept" msgid="1645267259272829559">"Aceptar"</string>
     <string name="decline" msgid="2112225451706137894">"Rechazar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitación enviada"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitación para conectarse"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"El tablet se desconectará temporalmente de la red Wi-Fi mientras esté conectado a  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Mientras el dispositivo Android TV esté conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, se desconectará temporalmente de la red Wi‑Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"El teléfono se desconectará temporalmente de la red Wi-Fi mientras está conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está enviando un gran número de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"El modo Ahorro de batería desactiva o restringe la actividad en segundo plano, así como algunos efectos visuales y otras funciones que consumen mucha batería para poder prolongar su duración. "<annotation id="url">"Más información"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"El modo Ahorro de batería desactiva o restringe la actividad en segundo plano, así como algunos efectos visuales y otras funciones que consumen mucha batería para poder prolongar su duración."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 a8f546d..a48c482 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Äratuse helid"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Märguannete helid"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Teadmata"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">WiFi-võrgud on saadaval</item>
-      <item quantity="one">WiFi-võrk on saadaval</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Avatud WiFi-võrgud on saadaval</item>
-      <item quantity="one">Avatud WiFi-võrk on saadaval</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Looge ühendus avatud WiFi-võrguga"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"WiFi-võrguga ühendamine"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ühendatud WiFi-võrguga"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"WiFi-võrguga ei õnnestunud ühendust luua"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Puudutage kõikide võrkude nägemiseks"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Ühenda"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Kõik võrgud"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Kas lubada soovitatud WiFi-võrgud?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Rakenduse <xliff:g id="NAME">%s</xliff:g> soovitatud võrgud. Seade võib automaatselt ühenduse luua."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Luba"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Tänan, ei"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"WiFi lülitub sisse automaatselt"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kui olete kvaliteetse salvestatud võrgu läheduses"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ära lülita tagasi sisse"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"WiFi lülitati automaatselt sisse"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Teie lähedal on salvestatud võrk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logi sisse WiFi-võrku"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Võrku sisselogimine"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ühendatud"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Võrgu <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ühendus on piiratud"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Puudutage, kui soovite siiski ühenduse luua"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Muudatused teie kuumkoha seadetes"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Teie kuumkoha sagedusriba on muutunud."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"See seade ei toeta teie eelistatud ainult 5 GHz riba. Seade kasutab 5 GHz riba ainult siis, kui see on saadaval."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Lülitati võrgule <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Seade kasutab võrku <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, kui võrgul <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> puudub juurdepääs Internetile. Rakenduda võivad tasud."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lülitati võrgult <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> võrgule <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tundmatu võrgutüüp"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" on halb Interneti-ühendus."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Kas lubada ühendus?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Rakendus %1$s soovib luua ühenduse WiFi-võrguga %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Rakendus"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/kuumkoha."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Puudutage seadete nägemiseks"</string>
     <string name="accept" msgid="1645267259272829559">"Nõustu"</string>
     <string name="decline" msgid="2112225451706137894">"Keeldu"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Kutse ühendamiseks"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Saatja:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tahvelarvuti ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ühendamisel katkestatakse ajutiselt Android TV seadme ühendus WiFi-võrguga."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefoni ühendus WiFi-ga katkestatakse ajutiselt, kui see on ühendatud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; saadab suurel hulgal SMS-sõnumeid. Kas tahate lubada sellel rakendusel ka edaspidi sõnumeid saata?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Aku tööea pikendamiseks lülitab akusäästja taustategevused, mõningad visuaalsed efektid ja muud akut koormavad funktsioonid välja või piirab neid. "<annotation id="url">"Lisateave"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Aku tööea pikendamiseks lülitab akusäästja taustategevused, mõningad visuaalsed efektid ja muud akut koormavad funktsioonid välja või piirab neid."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 d87bdfb..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>
@@ -325,7 +325,7 @@
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Egin keinuak"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
     <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Hatz-marken keinuak"</string>
-    <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Gailuaren hatz-marken sentsorean egindako keinuak antzeman ditzake."</string>
+    <string name="capability_desc_canCaptureFingerprintGestures" msgid="4386487962402228670">"Gailuaren hatz-marken sentsorean egindako keinuak atzeman ditzake."</string>
     <string name="permlab_statusBar" msgid="7417192629601890791">"desgaitu edo aldatu egoera-barra"</string>
     <string name="permdesc_statusBar" msgid="8434669549504290975">"Egoera-barra desgaitzea edo sistema-ikonoak gehitzea edo kentzea baimentzen die aplikazioei."</string>
     <string name="permlab_statusBarService" msgid="4826835508226139688">"bihurtu egoera-barra"</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>
@@ -936,7 +936,7 @@
     <string name="autofill_department" msgid="5343279462564453309">"Departamentua"</string>
     <string name="autofill_prefecture" msgid="2028499485065800419">"Prefektura"</string>
     <string name="autofill_parish" msgid="8202206105468820057">"Parrokia"</string>
-    <string name="autofill_area" msgid="3547409050889952423">"Zonaldea"</string>
+    <string name="autofill_area" msgid="3547409050889952423">"Eskualdea"</string>
     <string name="autofill_emirate" msgid="2893880978835698818">"Emirerria"</string>
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"irakurri sareko laster-markak eta historia"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Arakatzailearen bidez bisitatutako URL guztien historia eta arakatzailearen  laster-marka guztiak irakurtzeko baimena ematen die aplikazioei. Oharra: agian baimen hori ez dute aplikatuko hirugarrenen arakatzaileek edo sarea arakatzeko gaitasuna duten bestelako aplikazioek."</string>
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarma-soinuak"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Jakinarazpen-soinuak"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ezezaguna"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi sareak erabilgarri</item>
-      <item quantity="one">Wi-Fi sarea erabilgarri</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Wi-Fi sare irekiak erabilgarri</item>
-      <item quantity="one">Wi-Fi sare irekia erabilgarri</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Konektatu Wi‑Fi sare irekira"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi sarera konektatzen"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi sare irekira konektatuta"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Ezin izan da konektatu Wi‑Fi sare irekira"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Sakatu hau sare guztiak ikusteko"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Konektatu"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Sare guztiak"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Iradokitako wifi-sareak baimendu nahi dituzu?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> aplikazioak sare batzuk iradoki ditu. Baliteke gailua automatikoki konektatzea."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Baimendu"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ez, eskerrik asko"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi konexioa automatikoki aktibatuko da"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Gordeta daukazun kalitate handiko sare batetik gertu zaudenean"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ez aktibatu berriro"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Automatikoki aktibatu da Wi‑Fi konexioa"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Gordetako sare honetatik gertu zaude: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Hasi saioa Wi-Fi sarean"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Hasi saioa sarean"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Konektatuta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sareak konektagarritasun murriztua du"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Sakatu hala ere konektatzeko"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Aldaketak egin dira sare publikoaren ezarpenetan"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Aldatu da sare publikoaren banda."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Gailuak ez du onartzen 5 GHz-ko banda soilik erabiltzeko hobespena. Horren ordez, erabilgarri dagoen bakoitzean erabiliko da 5 GHz-ko banda."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> erabiltzen ari zara orain"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> Internetera konektatzeko gauza ez denean, <xliff:g id="NEW_NETWORK">%1$s</xliff:g> erabiltzen du gailuak. Agian kostuak ordaindu beharko dituzu."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> erabiltzen ari zinen, baina <xliff:g id="NEW_NETWORK">%2$s</xliff:g> erabiltzen ari zara orain"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"sare mota ezezaguna"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ezin izan da Wi-Fi sarera konektatu"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Konektatzeko baimena eman nahi diozu?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s aplikazioak %2$s Wi-Fi sarera konektatu nahi du"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikazio bat"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Hasi Wi-Fi Direct. Wi-Fi bezeroa edo sare publikoa desaktibatuko da."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Ezin izan da Wi-Fi Direct hasi."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct aktibatuta dago"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sakatu ezarpenak ikusteko"</string>
     <string name="accept" msgid="1645267259272829559">"Onartu"</string>
     <string name="decline" msgid="2112225451706137894">"Baztertu"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Gonbidapena bidali da"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Konektatzeko gonbidapena"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Igorlea:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Hartzailea:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Idatzi beharrezko PINa:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PINa:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta Wi-Fi saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV gailua wifi-saretik deskonektatuko da aldi batez <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonoa Wi-Fi saretik deskonektatuko da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailura konektatuta dagoen bitartean"</string>
     <string name="select_character" msgid="3365550120617701745">"Txertatu karakterea"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS mezuak bidaltzen"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; SMS asko ari da bidaltzen. Mezuak bidaltzen jarrai dezan onartu nahi duzu?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Bateria-aurrezlea desaktibatzen da, edo atzeko planoko jarduerak, zenbait efektu bisual eta bateria asko darabilten bestelako eginbideak murrizten dira, bateriak gehiago iraun dezan. "<annotation id="url">"Lortu informazio gehiago"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Bateria-aurrezlea desaktibatzen da, edo atzeko planoko jarduerak, zenbait efektu bisual eta bateria asko darabilten bestelako eginbideak murrizten dira, bateriak gehiago iraun dezan."</string>
+    <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>
@@ -1858,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>
@@ -2003,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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 16382638..98044c6 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -231,7 +231,7 @@
     <string name="global_action_logout" msgid="935179188218826050">"پایان جلسه"</string>
     <string name="global_action_screenshot" msgid="8329831278085426283">"عکس صفحه‌نمایش"</string>
     <string name="bugreport_title" msgid="5981047024855257269">"گزارش اشکال"</string>
-    <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به صورت یک پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً شکیبا باشید."</string>
+    <string name="bugreport_message" msgid="398447048750350456">"این گزارش اطلاعات مربوط به وضعیت دستگاه کنونی شما را جمع‌آوری می‌کند تا به‌صورت پیام ایمیل ارسال شود. از زمان شروع گزارش اشکال تا آماده شدن برای ارسال اندکی زمان می‌برد؛ لطفاً کمی صبر کنید."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"گزارش تعاملی"</string>
     <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"در بیشتر شرایط از این گزینه استفاده کنید. به شما امکان ردیابی پیشرفت گزارش و وارد کردن جزئیات بیشتری درباره مشکل را می‌دهد. ممکن است برخی از بخش‌هایی را که کمتر استفاده شده و باعث افزایش طول زمان گزارش می‌شود حذف کند."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"گزارش کامل"</string>
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"صداهای زنگ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"صداهای اعلان"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"نامشخص"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">‏شبکه Wi-Fi در دسترس</item>
-      <item quantity="other">‏شبکه‌ Wi-Fi در دسترس</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">‏شبکه Wi-Fi باز در دسترس</item>
-      <item quantity="other">‏شبکه‌ Wi-Fi باز در دسترس</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"‏اتصال به شبکه Wi‑Fi باز"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"‏درحال اتصال به شبکه Wi‑Fi..."</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"‏به شبکه Wi‑Fi متصل شد"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"‏به شبکه Wi-Fi متصل نشد"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"برای دیدن همه شبکه‌ها ضربه بزنید"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"اتصال"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"همه شبکه‌ها"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"‏شبکه‌های Wi‑Fi پیشنهادی مجاز شود؟"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"شبکه‌های پیشنهادی <xliff:g id="NAME">%s</xliff:g>. ممکن است دستگاه به‌طور خودکار متصل شود."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"مجاز"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"نه متشکرم"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"‏Wi‑Fi به‌طور خودکار روشن خواهد شد"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"وقتی نزدیک شبکه ذخیره‌شده با کیفیت بالا هستید"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"دوباره روشن نشود"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"‏Wi‑Fi به‌صورت خودکار روشن شد"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"نزدیک شبکه ذخیره‌شده‌ای هستید: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏ورود به شبکه Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ورود به سیستم شبکه"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"متصل"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> اتصال محدودی دارد"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"به‌هرصورت، برای اتصال ضربه بزنید"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"تغییرات در تنظیمات نقطه اتصال"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"نوار نقطه اتصال شما تغییر کرد."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"این دستگاه از اولویت فقط ۵ گیگاهرتز شما پشتیبانی نمی‌کند. هرزمان نوار ۵ گیگاهرتزی دردسترس باشد این دستگاه از آن استفاده خواهد کرد."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"به <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> تغییر کرد"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"وقتی <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> به اینترنت دسترسی نداشته باشد، دستگاه از <xliff:g id="NEW_NETWORK">%1$s</xliff:g> استفاده می‌کند. ممکن است هزینه‌هایی اعمال شود."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"از <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> به <xliff:g id="NEW_NETWORK">%2$s</xliff:g> تغییر کرد"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نوع شبکه نامشخص"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏اتصال به Wi-Fi ممکن نیست"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" اتصال اینترنتی ضعیفی دارد."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"اتصال مجاز است؟"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏برنامه %1$s می‌خواهد به شبکه Wifi ‏%2$s وصل شود"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"برنامه"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏Wi-Fi Direct شروع نشد."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"‏Wi-Fi Direct روشن است"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"برای تنظیمات ضربه بزنید"</string>
     <string name="accept" msgid="1645267259272829559">"پذیرفتن"</string>
     <string name="decline" msgid="2112225451706137894">"نپذیرفتن"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"دعوت‌نامه ارسال شد"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"دعوت‌نامه برای اتصال"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"از:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"به:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"‏در حین اتصال به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ارتباط این رایانه لوحی با Wi-Fi موقتاً قطع خواهد شد."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"‏وقتی دستگاه Android TV به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> متصل است، اتصال آن به Wi-Fi موقتاً قطع می‌شود"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"‏این گوشی به‌طور موقت از Wi-Fi قطع خواهد شد، در حالی که به <xliff:g id="DEVICE_NAME">%1$s</xliff:g> وصل است"</string>
     <string name="select_character" msgid="3365550120617701745">"درج نویسه"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"درحال ارسال پیامک‌ها"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; درحال ارسال تعداد زیادی پیامک است. آیا اجازه می‌دهید این برنامه همچنان پیامک ارسال کند؟"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"«بهینه‌سازی باتری» فعالیت پس‌زمینه، برخی جلوه‌های دیداری، و سایر ویژگی‌های پرمصرف نیرو را خاموش یا محدود می‌کند تا عمر باتری افزایش یابد. "<annotation id="url">"بیشتر بدانید"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"«بهینه‌سازی باتری» فعالیت پس‌زمینه، برخی جلوه‌های دیداری، و سایر ویژگی‌های پرمصرف نیرو را خاموش یا محدود می‌کند تا عمر باتری افزایش یابد."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 5b050c3..3476bf5 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Hälytysäänet"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ilmoitusäänet"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Tuntematon"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi-verkkoja käytettävissä</item>
-      <item quantity="one">Wi-Fi-verkko käytettävissä</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Avoimia Wi-Fi-verkkoja käytettävissä</item>
-      <item quantity="one">Avoin Wi-Fi-verkko käytettävissä</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Yhdistä avoimeen Wi‑Fi-verkkoon"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Yhdistetään Wi-Fi-verkkoon"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Yhdistetty Wi-Fi-verkkoon"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi-verkkoon yhdistäminen epäonnistui"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Napauta, niin näet kaikki verkot."</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Yhdistä"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Kaikki verkot"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Sallitaanko ehdotetut Wi-Fi-verkot?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ehdotti verkkoja. Laite voi muodostaa yhteyden automaattisesti."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Salli"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ei kiitos"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi käynnistyy automaattisesti"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kun olet lähellä laadukasta tallennettua verkkoa"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Älä käynnistä uudelleen"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi otettiin käyttöön automaattisesti"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Olet lähellä tallennettua verkkoa: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kirjaudu Wi-Fi-verkkoon"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Kirjaudu verkkoon"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Yhdistetty"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> toimii rajoitetulla yhteydellä"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Yhdistä napauttamalla"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot-asetustesi muutokset"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot-taajuutesi on muuttunut."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Tämä laite ei tue asetustasi (vain 5 GHz). Sen sijaan laite käyttää 5 GHz:n taajuutta sen ollessa käytettävissä."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> otettiin käyttöön"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> otetaan käyttöön, kun <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ei voi muodostaa yhteyttä internetiin. Veloitukset ovat mahdollisia."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> poistettiin käytöstä ja <xliff:g id="NEW_NETWORK">%2$s</xliff:g> otettiin käyttöön."</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tuntematon verkon tyyppi"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-yhteyden muodostaminen epäonnistui"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" : huono internetyhteys."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Sallitaanko yhteys?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Sovellus %1$s yrittää yhdistää Wi-Fi-verkkoon %2$s."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Sovellus"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora Wi-Fi-yhteys. Wi-Fi-asiakas/-hotspot poistetaan käytöstä."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran Wi-Fi-yhteyden käynnistäminen epäonnistui."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Näytä asetukset napauttamalla."</string>
     <string name="accept" msgid="1645267259272829559">"Hyväksy"</string>
     <string name="decline" msgid="2112225451706137894">"Hylkää"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutsu lähetetty."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Yhdistämiskutsu"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Lähde:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kohde:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet-laitteen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti tabletin ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV ‑laitteen Wi-Fi-yhteys katkeaa tilapäisesti, kun siihen on yhdistetty <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Puhelimen yhteys Wi-Fi-verkkoon katkaistaan väliaikaisesti puhelimen ollessa yhdistettynä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; lähettää suuria määriä tekstiviestejä. Annetaanko tämän sovelluksen jatkaa tekstiviestien lähettämistä?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Virransäästö poistaa käytöstä taustatoiminnot, joitakin visuaalisia tehosteita ja muita virtaa runsaasti kuluttavia ominaisuuksia tai rajoittaa niitä akunkeston pidentämiseksi. "<annotation id="url">"Lue lisää"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Virransäästö poistaa käytöstä taustatoiminnot, joitakin visuaalisia tehosteita ja muita virtaa runsaasti kuluttavia ominaisuuksia tai rajoittaa niitä akunkeston pidentämiseksi."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 02c8043..702ecc0 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons d\'alarme"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Inconnu"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Réseau Wi-Fi à proximité</item>
-      <item quantity="other">Réseaux Wi-Fi à proximité</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Réseau Wi-Fi ouvert à proximité</item>
-      <item quantity="other">Réseaux Wi-Fi ouverts à proximité</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Connectez-vous pour ouvrir un réseau Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connexion au réseau Wi-Fi en cours…"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connecté au réseau Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Impossible de se connecter au réseau Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Touchez pour afficher tous les réseaux"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connexion"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Tous les réseaux"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Autoriser les suggestions de réseaux Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Réseaux suggérés par <xliff:g id="NAME">%s</xliff:g>. L\'appareil peut s\'y connecter automatiquement."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Autoriser"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Non merci"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Le Wi-Fi s\'activera automatiquement"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Lorsque vous êtes près d\'un réseau enregistré de haute qualité"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ne pas réactiver"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi activé automatiquement"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Vous êtes à proximité d\'un réseau enregistré : <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Connectez-vous au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connecté"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Le réseau <xliff:g id="NETWORK_SSID">%1$s</xliff:g> offre une connectivité limitée"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Touchez pour vous connecter quand même"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifications apportées à vos paramètres de point d\'accès"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La bande de votre point d\'accès a changé."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Cet appareil ne prend pas en charge votre préférence pour la bande de 5 GHz seulement. Au lieu de cela, cet appareil utilisera la bande de 5 GHz lorsqu\'elle sera disponible."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Passé au réseau <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quand <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas d\'accès à Internet. Des frais peuvent s\'appliquer."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passé du réseau <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> au <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"RPV"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un type de réseau inconnu"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" dispose d\'une connexion Internet faible."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Touchez pour accéder aux paramètres"</string>
     <string name="accept" msgid="1645267259272829559">"Accepter"</string>
     <string name="decline" msgid="2112225451706137894">"Refuser"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation envoyée"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation à se connecter"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De :"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"À :"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le NIP requis :"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"NIP :"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tablette sera déconnectée du réseau Wi-Fi tant qu\'elle sera connectée à l\'appareil \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Votre appareil Android TV se déconnectera temporairement du Wi-Fi lors de sa connexion à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envoie un grand nombre de SMS. Autorisez-vous cette application à poursuivre l\'envoi des messages?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Le mode Économiseur de pile désactive ou restreint l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités qui consomment beaucoup d\'énergie afin de prolonger l\'autonomie de la pile. "<annotation id="url">"En savoir plus"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Le mode Économiseur de pile désactive ou restreint l\'activité en arrière-plan, certains effets visuels et d\'autres fonctionnalités qui consomment beaucoup d\'énergie afin de prolonger l\'autonomie de la pile."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 b5b0a56..eb199de 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de l\'alarme"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notification"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Inconnue"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Réseau Wi-Fi disponible</item>
-      <item quantity="other">Réseaux Wi-Fi disponibles</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Réseau Wi-Fi ouvert disponible</item>
-      <item quantity="other">Réseaux Wi-Fi ouverts disponibles</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Se connecter pour ouvrir le réseau Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connexion au réseau Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connecté au réseau Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Impossible de se connecter au réseau Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Appuyer pour afficher tous les réseaux"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Se connecter"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Tous les réseaux"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Autoriser les suggestions de réseaux Wi‑Fi ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Réseaux suggérés par <xliff:g id="NAME">%s</xliff:g>. L\'appareil pourra se connecter automatiquement."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Autoriser"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Non, merci"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Le Wi-Fi sera activé automatiquement"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Lorsque vous êtes à proximité d\'un réseau enregistré de haute qualité"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ne pas réactiver"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi activé automatiquement"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Vous vous trouvez à proximité d\'un réseau enregistré : <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Connectez-vous au réseau Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Se connecter au réseau"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connecté"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"La connectivité de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> est limitée"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Appuyer pour se connecter quand même"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifications apportées à vos paramètres de point d\'accès"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Votre bande de point d\'accès a été modifiée."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Cet appareil n\'est pas compatible avec votre préférence d\'utilisation de la bande 5 GHz uniquement. Il utilisera la bande 5 GHz lorsqu\'elle sera disponible."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Nouveau réseau : <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"L\'appareil utilise <xliff:g id="NEW_NETWORK">%1$s</xliff:g> lorsque <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> n\'a pas de connexion Internet. Des frais peuvent s\'appliquer."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Ancien réseau : <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>. Nouveau réseau : <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"type de réseau inconnu"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" dispose d\'une mauvaise connexion Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Autoriser la connexion ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'application %1$s souhaite se connecter au réseau Wi-Fi %2$s."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Une application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Appuyez ici pour accéder aux paramètres."</string>
     <string name="accept" msgid="1645267259272829559">"Accepter"</string>
     <string name="decline" msgid="2112225451706137894">"Refuser"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation envoyée"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitation à se connecter"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De :"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"À :"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code :"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"La tablette sera déconnectée du réseau Wi-Fi tant qu\'elle sera connectée à l\'appareil \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Votre appareil Android TV se déconnectera temporairement du Wi-Fi lors de sa connexion à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Le téléphone sera déconnecté du réseau Wi-Fi tant qu\'il sera connecté à l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envoie un grand nombre de SMS. Autorisez-vous cette application à poursuivre l\'envoi des messages ?"</string>
@@ -1817,8 +1771,10 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Mis à 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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"L\'économiseur de batterie désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités qui consomment beaucoup d\'énergie afin de prolonger l\'autonomie de la batterie. "<annotation id="url">"En savoir plus"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"L\'économiseur de batterie désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités qui consomment beaucoup d\'énergie afin de prolonger l\'autonomie de la batterie."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <string name="data_saver_description" msgid="6015391409098303235">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</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>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 bf3b3bd..9659973 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificación"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Descoñecido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Redes wifi dispoñibles</item>
-      <item quantity="one">Rede wifi dispoñible</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Abrir redes wifi dispoñibles</item>
-      <item quantity="one">Abrir rede wifi dispoñible</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conéctate a unha rede wifi aberta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Conectándose á rede wifi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Conectouse á rede wifi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Non se puido conectar á rede wifi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toca para ver todas as redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectarse"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas as redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Queres permitir as redes wifi suxeridas?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Redes suxeridas de <xliff:g id="NAME">%s</xliff:g>. O dispositivo pode conectarse automaticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Non, grazas"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"A wifi activarase automaticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Cando esteas preto dunha rede gardada de alta calidade"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Non volver activar"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Activouse a wifi automaticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Estás preto dunha rede gardada: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inicia sesión na rede wifi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inicia sesión na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Estableceuse conexión"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"A conectividade de <xliff:g id="NETWORK_SSID">%1$s</xliff:g> é limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toca para conectarte de todas formas"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Cambios na configuración da zona wifi"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Modificouse a banda da zona wifi."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo non admite a opción de conectarse só a bandas de 5 GHz, pero usaraas se están dispoñibles."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Cambiouse a: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> cando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ten acceso a Internet. Pódense aplicar cargos."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Cambiouse de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tipo de rede descoñecido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Non se puido conectar á wifi"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Queres permitir a conexión?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicación %1$s quere conectarse á rede wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Unha aplicación"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Esta acción desactivará a zona ou o cliente wifi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Non se puido iniciar Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct está activado"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toca para acceder á configuración"</string>
     <string name="accept" msgid="1645267259272829559">"Aceptar"</string>
     <string name="decline" msgid="2112225451706137894">"Rexeitar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitación enviada"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitación para conectarse"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe o PIN obrigatorio:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"A tableta desconectarase temporalmente da wifi mentres está conectada a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"O dispositivo Android TV desconectarase temporalmente da wifi mentres estea conectado a: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O teléfono desconectarase temporalmente da wifi mentres está conectado con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserir carácter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensaxes SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está enviando moitas mensaxes SMS. Queres permitir que esta aplicación siga enviando mensaxes?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A función Aforro de batería desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións que consomen moita batería para que esta dure máis. "<annotation id="url">"Máis información"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A función Aforro de batería desactiva ou restrinxe a actividade en segundo plano, algúns efectos visuais e outras funcións que consomen moita batería para que esta dure máis."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 66bba23..6dab622 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"એલાર્મ ધ્વનિઓ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"સૂચના ધ્વનિઓ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"અજાણી"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ</item>
-      <item quantity="other">વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">ખુલ્લા વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ છે</item>
-      <item quantity="other">ખુલ્લા વાઇ-ફાઇ નેટવર્ક્સ ઉપલબ્ધ છે</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ખુલ્લા વાઇ-ફાઇ નેટવર્ક સાથે કનેક્ટ કરો"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"કનેક્ટ કરી રહ્યાં છીએ તે વાઇ-ફાઇ નેટવર્ક"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"વાઇ-ફાઇ નેટવર્ક સાથે કનેક્ટ કર્યુ"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"વાઇ-ફાઇ નેટવર્ક સાથે કનેક્ટ કરી શકાયું નથી"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"બધા નેટવર્ક જોવા ટૅપ કરો"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"કનેક્ટ કરો"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"બધા નેટવર્કો"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"સૂચવેલા વાઇ-ફાઇ નેટવર્કને મંજૂરી આપીએ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> સૂચવેલા નેટવર્ક. ડિવાઇસ ઑટોમૅટિક રીતે કનેક્ટ થાય તેમ બની શકે છે."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"મંજૂરી આપો"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ના, આભાર"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"વાઇ-ફાઇ આપમેળે ચાલુ થઈ જશે"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"જ્યારે તમે એક ઉચ્ચ ક્વૉલિટીવાળા સાચવેલ નેટવર્કની નજીક હોવ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"પાછું ચાલુ કરશો નહીં"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"વાઇ-ફાઇ આપમેળે ચાલુ થયું"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"તમે એક સાચવેલ નેટવર્કની નજીકમાં છો: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"વાઇ-ફાઇ નેટવર્ક પર સાઇન ઇન કરો"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"નેટવર્ક પર સાઇન ઇન કરો"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"કનેક્ટેડ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> મર્યાદિત કનેક્ટિવિટી ધરાવે છે"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"છતાં કનેક્ટ કરવા માટે ટૅપ કરો"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"તમારી હૉટસ્પૉટ સેટિંગને બદલે છે"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"તમારું હૉટસ્પૉટ બેન્ડ બદલાયેલ છે."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"આ ઉપકરણ તમારી ફક્ત 5GHz માટેની પસંદગીને સમર્થન આપતું નથી. તેના બદલે, જ્યારે આ ઉપકરણ જ્યારે 5GHz બેન્ડ ઉપલબ્ધ હશે ત્યારે તેનો ઉપયોગ કરશે."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> પર સ્વિચ કર્યું"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"જ્યારે <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> પાસે કોઈ ઇન્ટરનેટ ઍક્સેસ ન હોય ત્યારે ઉપકરણ <xliff:g id="NEW_NETWORK">%1$s</xliff:g>નો ઉપયોગ કરે છે. શુલ્ક લાગુ થઈ શકે છે."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> પરથી <xliff:g id="NEW_NETWORK">%2$s</xliff:g> પર સ્વિચ કર્યું"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"અજાણ્યો નેટવર્ક પ્રકાર"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"વાઇ-ફાઇ સાથે કનેક્ટ કરી શકાયું નથી"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"કનેક્શનની મંજૂરી આપીએ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ઍપ્લિકેશન Wifi નેટવર્ક %2$s થી કનેક્ટ થવા માગે છે"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ઍપ્લિકેશન"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"વાઇ-ફાઇ ડાઇરેક્ટ"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"વાઇ-ફાઇ ડાઇરેક્ટ પ્રારંભ કરો. આ વાઇ-ફાઇ ક્લાઇન્ટ/હોટસ્પોટને બંધ કરશે."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"વાઇ-ફાઇ ડાઇરેક્ટ પ્રારંભ કરી શકાયું નથી."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"વાઇ-ફાઇ ડાઇરેક્ટ ચાલુ છે"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"સેટિંગ્સ માટે ટૅપ કરો"</string>
     <string name="accept" msgid="1645267259272829559">"સ્વીકારો"</string>
     <string name="decline" msgid="2112225451706137894">"નકારો"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"આમંત્રણ મોકલ્યું"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"કનેક્ટ થવા માટે આમંત્રણ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"મોકલનાર:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"પ્રતિ:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"આવશ્યક પિન લખો:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"પિન:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ટેબ્લેટ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇ થી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"તમારું Android TV ડિવાઇસ, <xliff:g id="DEVICE_NAME">%1$s</xliff:g>થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇથી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ફોન <xliff:g id="DEVICE_NAME">%1$s</xliff:g> થી કનેક્ટ હોય તે વખતે વાઇ-ફાઇ થી અસ્થાયી રૂપે ડિસ્કનેક્ટ કરવામાં આવશે"</string>
     <string name="select_character" msgid="3365550120617701745">"અક્ષર શામેલ કરો"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS સંદેશા મોકલી રહ્યું છે"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; મોટા પ્રમાણમાં SMS સંદેશા મોકલી રહ્યું છે. શું તમે સંદેશા મોકલવાનું ચાલુ રાખવા માટે આ એપ્લિકેશનને મંજૂરી આપવા માગો છો?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"બૅટરી આવરદા વધારવા માટે, બૅટરી સેવર બૅકગ્રાઉન્ડ પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ અસરો અને અન્ય હાઇ-પાવર સુવિધાઓ બંધ અથવા મર્યાદિત કરે છે. "<annotation id="url">"વધુ જાણો"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"બૅટરી આવરદા વધારવા માટે, બૅટરી સેવર બૅકગ્રાઉન્ડ પ્રવૃત્તિ, કેટલીક વિઝ્યુઅલ અસરો અને અન્ય હાઇ-પાવર સુવિધાઓ બંધ અથવા મર્યાદિત કરે છે."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 717c7ae..1a082b9 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनियां"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना की आवाज़"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
-      <item quantity="other">वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
-      <item quantity="other">खुले वाई-फ़ाई नेटवर्क उपलब्‍ध</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"खुले वाई-फ़ाई नेटवर्क से कनेक्ट करें"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"वाई-फ़ाई नेटवर्क से जोड़ा जा रहा है"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"वाई-फ़ाई नेटवर्क से कनेक्‍ट हो गया है"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"वाई-फ़ाई  नेटवर्क से कनेक्‍ट नहीं हो सका"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"सभी नेटवर्क देखने के लिए यहां पर टैप करें"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"कनेक्ट करें"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"सभी नेटवर्क"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"सुझाए गए वाई-फ़ाई नेटवर्क को अनुमति देना चाहते हैं?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> के सुझाए गए नेटवर्क. डिवाइस अपने आप कनेक्ट हो सकता है."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"अनुमति दें"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"रहने दें"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"वाई-फ़ाई अपने आप चालू हो जाएगा"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"जब आप किसी अच्छी क्वालिटी वाले सेव किए गए नेटवर्क के पास हों"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"वापस चालू न करें"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"वाई-फ़ाई अपने आप चालू हो गया है"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"आप एक सेव किए गए नेटवर्क के पास हैं: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"वाई-फ़ाई  नेटवर्क में साइन इन करें"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्क में साइन इन करें"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"जुड़ गया है"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> की कनेक्टिविटी सीमित है"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"फिर भी कनेक्ट करने के लिए टैप करें"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"आपकी हॉटस्पॉट सेटिंग के हिसाब से बदलाव हो गए हैं"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"आपका हॉटस्पॉट बैंड बदल गया है."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"यह डिवाइस सिर्फ़ 5 गीगाहर्ट्ज़ की आपकी पसंद की सेटिंग पर काम नहीं करता, लेकिन जब भी 5 गीगाहर्ट्ज़ बैंड मौजूद होगा, डिवाइस उसका इस्तेमाल करने लगेगा."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> पर ले जाया गया"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> में इंटरनेट की सुविधा नहीं होने पर डिवाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> का इस्तेमाल करता है. इसके लिए शुल्क लिया जा सकता है."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> से <xliff:g id="NEW_NETWORK">%2$s</xliff:g> पर ले जाया गया"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"वीपीएन"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाई-फ़ाई  से कनेक्‍ट नहीं हो सका"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शन की अनुमति दें?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ऐप्‍लिकेशन %2$s वाई-फ़ाई नेटवर्क से कनेक्‍ट करना चाहता है"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ऐप्लिकेशन"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाई-फ़ाई डायरेक्ट"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाई-फ़ाई डायरेक्ट चालू करें. इससे वाई-फ़ाई क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाई-फ़ाई  डायरेक्ट प्रारंभ नहीं किया जा सका."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"वाई-फ़ाई डायरेक्ट चालू है"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"सेटिंग के लिए टैप करें"</string>
     <string name="accept" msgid="1645267259272829559">"स्वीकार करें"</string>
     <string name="decline" msgid="2112225451706137894">"अस्वीकार करें"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"आमंत्रण भेजा गया"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"कनेक्‍ट करने का आमंत्रण"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"प्रेषक:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रति:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्‍यक पिन लिखें:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहने पर टैबलेट वाई-फ़ाई  से अस्थायी रूप से डिसकनेक्ट हो जाएगा"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>से कनेक्ट रहने के दौरान आपका Android TV डिवाइस, Wi-Fi से अस्थायी रूप से डिसकनेक्ट हो जाएगा."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"फ़ोन <xliff:g id="DEVICE_NAME">%1$s</xliff:g> से कनेक्ट रहते समय वाई-फ़ाई  से अस्थायी रूप से डिसकनेक्ट हो जाएगा"</string>
     <string name="select_character" msgid="3365550120617701745">"वर्ण सम्‍मिलित करें"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"मैसेज (एसएमएस) भेज रहा है"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; बड़ी संख्या में मैसेज (एसएमएस) भेज रहा है. क्या आप इस ऐप को मैसेज भेजना जारी रखने देना चाहते हैं?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"बैटरी सेवर बंद हो जाता है या बैटरी लाइफ़ बढ़ाने के लिए बैकग्राउंड गतिविधि, कुछ विजुअल इफ़ेक्ट और ज़्यादा बैटरी इस्तेमाल करने वाली सुविधाओं पर पाबंदी लग जाती है. "<annotation id="url">"ज़्यादा जानें"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"बैटरी सेवर बंद हो जाता है या बैटरी लाइफ़ बढ़ाने के लिए बैकग्राउंड गतिविधि, कुछ विजुअल इफ़ेक्ट और ज़्यादा बैटरी इस्तेमाल करने वाली सुविधाओं पर पाबंदी लग जाती है."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 00da024..56d5b20 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1264,32 +1264,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvukovi alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvukovi obavijesti"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nepoznato"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Dostupne su Wi-Fi mreže</item>
-      <item quantity="few">Dostupne su Wi-Fi mreže</item>
-      <item quantity="other">Dostupne su Wi-Fi mreže</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Dostupne su otvorene Wi-Fi mreže</item>
-      <item quantity="few">Dostupne su otvorene Wi-Fi mreže</item>
-      <item quantity="other">Dostupne su otvorene Wi-Fi mreže</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Povezivanje s otvorenom Wi‑Fi mrežom"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Povezivanje s Wi-Fi mrežom"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Povezano s Wi-Fi mrežom"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nije uspjelo povezivanje s Wi-Fi mrežom"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Dodirnite za prikaz svih mreža"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Poveži"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Sve mreže"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Želite li dopustiti predložene Wi‑Fi mreže?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Mreže koje predlaže aplikacija <xliff:g id="NAME">%s</xliff:g>. Uređaji se mogu povezati automatski."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Dopusti"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, hvala"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi će se uključiti automatski"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kada ste u blizini spremljene mreže visoke kvalitete"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Više ne uključuj"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi je uključen automatski"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Nalazite se u blizini spremljene mreže: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijava na Wi-Fi mrežu"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava na mrežu"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1302,9 +1276,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezano"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ima ograničenu povezivost"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dodirnite da biste se ipak povezali"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Promjene postavki vaše žarišne točke"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Promijenila se frekvencija vaše žarišne točke."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ovaj uređaj ne podržava vašu postavku za upotrebu samo 5 GHz. Upotrebljavat će frekvenciju od 5 GHz kada je dostupna."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Prelazak na drugu mrežu: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Kada <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nema pristup internetu, na uređaju se upotrebljava <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Moguća je naplata naknade."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mreža je promijenjena: <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> &gt; <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,27 +1287,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nepoznata vrsta mreže"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima lošu internetsku vezu."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Dopustiti povezivanje?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s traži povezivanje s Wi-Fi mrežom %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Pokretanje izravne Wi-Fi veze nije moguće."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dodirnite za postavke"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvaćam"</string>
     <string name="decline" msgid="2112225451706137894">"Odbaci"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslana"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozivnica za povezivanje"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Šalje:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV uređaj privremeno će prekinuti vezu s Wi-Fijem dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon će se privremeno isključiti s Wi-Fija dok je povezan s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Umetni znak"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikacija &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; šalje veliki broj SMS poruka. Želite li dopustiti ovoj aplikaciji da nastavi slati poruke?"</string>
@@ -1842,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Štednja baterije isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke koje troše mnogo energije kako bi se produljilo trajanje baterije. "<annotation id="url">"Saznajte više"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Štednja baterije isključuje ili ograničava aktivnosti u pozadini, neke vizualne efekte i druge značajke koje troše mnogo energije kako bi se produljilo trajanje baterije."</string>
+    <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>
@@ -2087,4 +2039,23 @@
     </plurals>
     <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 2958ca6..184b66a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ébresztőhangok"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Értesítőhangok"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ismeretlen"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi hálózatok érhetők el</item>
-      <item quantity="one">Van elérhető Wi-Fi hálózat</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Nyílt Wi-Fi hálózatok érhetők el</item>
-      <item quantity="one">Nyílt Wi-Fi hálózat érhető el</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Nyílt Wi-Fi-hálózathoz kapcsolódhat"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Csatlakozás Wi-Fi hálózathoz…"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Sikeres kapcsolódás a Wi-Fi-hálózathoz"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nem sikerült kapcsolódni a Wi‑Fi-hálózathoz"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Koppintással megjelenítheti az összes hálózatot"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Kapcsolódás"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Összes hálózat"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Engedélyezi a javasolt Wi-Fi-hálózatokat?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"A(z) <xliff:g id="NAME">%s</xliff:g> hálózatokat javasolt. Az eszköz automatikusan csatlakozhat hozzájuk."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Engedélyezés"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nem, köszönöm"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"A Wi-Fi automatikusan bekapcsol"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Amikor jó minőségű mentett hálózat közelében tartózkodik"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ne kapcsolódjon vissza"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi automatikusan bekapcsolva"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ön a következő mentett hálózat közelében tartózkodik: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Bejelentkezés Wi-Fi hálózatba"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Bejelentkezés a hálózatba"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Csatlakozva"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"A(z) <xliff:g id="NETWORK_SSID">%1$s</xliff:g> hálózat korlátozott kapcsolatot biztosít"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Koppintson, ha mindenképpen csatlakozni szeretne"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"A hotspot beállításainak módosítása"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"A hotspot sávja megváltozott."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ez az eszköz nem támogatja a csak 5 GHz-es sávra vonatkozó beállítást. Az eszköz akkor használ 5 GHz-es sávot, ha a sáv rendelkezésre áll."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Átváltva erre: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> használata, ha nincs internet-hozzáférés <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-kapcsolaton keresztül. A szolgáltató díjat számíthat fel."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Átváltva <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-hálózatról erre: <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ismeretlen hálózati típus"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" rossz internetkapcsolattal rendelkezik."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Engedélyezi a csatlakozást?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A(z) %1$s alkalmazás szeretne csatlakozni a következő Wi-Fi hálózathoz: %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Egy alkalmazás"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nem sikerült elindítani a Wi-Fi Direct kapcsolatot."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Koppintson a beállításokért"</string>
     <string name="accept" msgid="1645267259272829559">"Elfogadás"</string>
     <string name="decline" msgid="2112225451706137894">"Elutasítás"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Meghívó elküldve"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Meghívó csatlakozásra"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Feladó:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Címzett:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kód:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"A táblagép ideiglenesen lecsatlakozik a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Az Android TV eszköz ideiglenesen bontja a Wi-Fi-kapcsolatot arra az időre, amíg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"A telefon ideiglenesen kilép a Wi-Fi hálózatról, míg a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközhöz csatlakozik."</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/ b&gt; nagyszámú SMS üzenetet küld. Engedélyezi, hogy ez az alkalmazás továbbra is üzeneteket küldjön?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket és a sok energiát igénylő funkciókat. "<annotation id="url">"További információ."</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Az Akkumulátorkímélő mód az akkumulátor üzemidejének növelése érdekében kikapcsolja vagy korlátozza a háttérben futó tevékenységeket, egyes vizuális effekteket és a sok energiát igénylő funkciókat."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 967ddd0..fef6f4e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Զարթուցիչի զանգերանգներ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Ծանուցման զանգերանգներ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Անհայտ է"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Հասանելի են Wi-Fi ցանցեր</item>
-      <item quantity="other">Հասանելի են Wi-Fi ցանցեր</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
-      <item quantity="other">Հասանելի են չպաշտպանված Wi-Fi ցանցեր</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Միացեք բաց Wi‑Fi ցանցին"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Միացում Wi‑Fi ցանցին"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Միացել է Wi‑Fi ցանցին"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Չհաջողվեց միանալ Wi‑Fi ցանցին"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Հպեք՝ բոլոր ցանցերը տեսնելու համար"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Միանալ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Բոլոր ցանցերը"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Թույլատրե՞լ առաջարկվող Wi‑Fi ցանցերի օգտագործումը"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> հավելվածի առաջարկվող ցանցեր: Սարքը կարող է ավտոմատ միանալ:"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Թույլատրել"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ոչ, շնորհակալություն"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi-ն ավտոմատ կմիանա"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Լավ ազդանշանով պահված ցանցի տարածքում գտնվելիս"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Նորից չմիացնել"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi-ը միացել է ավտոմատ կերպով"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Դուք գտնվում եք պահված ցանցի մոտակայքում՝ <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Մուտք գործեք Wi-Fi ցանց"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Մուտք գործեք ցանց"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Միացված է"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ցանցի կապը սահմանափակ է"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Հպեք՝ միանալու համար"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Փոփոխություններ թեժ կետի կարգավորումներում"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ձեր թեժ կետի հաճախականությունը փոխվել է։"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Սարքը չի կարող աշխատել միայն 5 ԳՀց հաճախականությամբ։ Այդ հաճախականությունը կօգտագործվի հնարավորության դեպքում։"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Անցել է <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ցանցի"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Երբ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ցանցում ինտերնետ կապ չի լինում, սարքն անցնում է <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ցանցի: Նման դեպքում կարող են վճարներ գանձվել:"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ցանցից անցել է <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ցանցի"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ցանցի անհայտ տեսակ"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Չհաջողվեց միանալ Wi-Fi-ին"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ինտերնետային կապը թույլ է:"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Թույլատրե՞լ կապը:"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s հավելվածը ցանկանում է միանալ %2$s Wifi ցանցին"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Հավելված"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Մեկնարկել Wi-Fi ուղին: Այն կանջատի Wi-Fi հաճախորդ/թեժ կետ գործողությունը:"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Չհաջողվեց մեկնարկել Wi-Fi ուղին:"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ուղիղն առցանց է"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Հպեք՝ կարգավորելու համար"</string>
     <string name="accept" msgid="1645267259272829559">"Ընդունել"</string>
     <string name="decline" msgid="2112225451706137894">"Մերժել"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Հրավերն ուղարկված է"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Միացման հրավեր"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Ուղարկող`"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Ում`"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Մուտքագրեք պահանջվող PIN-ը:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-ը`"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Գրասալիկը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն կապակցված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Ձեր Android TV սարքը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն միացված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Հեռախոսը ժամանակավորապես կանջատվի Wi-Fi-ից, քանի դեռ այն միացված է <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ին"</string>
     <string name="select_character" msgid="3365550120617701745">"Զետեղել նշան"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS հաղորդագրությունների ուղարկում"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;-ը ուղարկում է մեծ թվով SMS հաղորդագրություններ: Ցանկանու՞մ եք թույլատրել այս հավելվածին շարունակել ուղարկել հաղորդագրություններ:"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Մարտկոցի աշխատաժամանակը երկարացնելու համար մարտկոցի տնտեսման ռեժիմն անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ տեսողական էֆեկտներ և էներգատար այլ գործառույթներ։ "<annotation id="url">"Իմանալ ավելին"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Մարտկոցի աշխատաժամանակը երկարացնելու համար մարտկոցի տնտեսման ռեժիմն անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ տեսողական էֆեկտներ և էներգատար այլ գործառույթներ։"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 662a654..87a8804 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suara alarm"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suara notifikasi"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Jaringan Wi-Fi tersedia</item>
-      <item quantity="one">Jaringan Wi-Fi tersedia</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Jaringan Wi-Fi terbuka tersedia</item>
-      <item quantity="one">Jaringan Wi-Fi terbuka tersedia</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Hubungkan ke jaringan Wi-Fi terbuka"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Menghubungkan ke jaringan Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Terhubung ke jaringan Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Tidak dapat menghubungkan ke jaringan Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Ketuk untuk melihat semua jaringan"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Hubungkan"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Semua jaringan"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Izinkan jaringan Wi-Fi yang disarankan?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Jaringan yang disarankan <xliff:g id="NAME">%s</xliff:g>. Perangkat dapat terhubung secara otomatis."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Izinkan"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Lain kali"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi akan aktif otomatis"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Saat berada di dekat jaringan berkualitas tinggi yang tersimpan"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Jangan aktifkan kembali"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi diaktifkan otomatis"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Anda berada di dekat jaringan yang tersimpan: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Login ke jaringan Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Login ke jaringan"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tersambung"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> memiliki konektivitas terbatas"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ketuk untuk tetap menyambungkan"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Perubahan pada setelan hotspot Anda"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pita hotspot Anda telah berubah."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Perangkat ini tidak mendukung preferensi Anda, yaitu hanya 5GHz. Sebagai gantinya, perangkat ini akan menggunakan pita frekuensi 5GHz jika tersedia."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Dialihkan ke <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Perangkat menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> jika <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tidak memiliki akses internet. Tarif mungkin berlaku."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Dialihkan dari <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ke <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis jaringan yang tidak dikenal"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" memiliki sambungan internet yang buruk."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Izinkan hubungan?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin tersambung ke Jaringan Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikasi"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Direct. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulai Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct aktif"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Ketuk untuk setelan"</string>
     <string name="accept" msgid="1645267259272829559">"Terima"</string>
     <string name="decline" msgid="2112225451706137894">"Tolak"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Undangan terkirim"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Undangan untuk terhubung"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Dari:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Sambungan tablet akan diputuskan dari Wi-Fi untuk sementara saat tersambung dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Perangkat Android TV akan memutuskan hubungan sementara dari Wi-Fi saat terhubung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Ponsel akan terputus sementara dari Wi-Fi saat tersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sedang mengirim pesan SMS dalam jumlah besar. Izinkan aplikasi ini untuk melanjutkan pengiriman pesan?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Penghemat Baterai menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual &amp; fitur lain yang menggunakan banyak daya untuk memperpanjang masa pakai baterai. "<annotation id="url">"Pelajari Lebih Lanjut"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Penghemat Baterai menonaktifkan atau membatasi aktivitas di latar belakang, beberapa efek visual &amp; fitur lain yang menggunakan banyak daya untuk memperpanjang masa pakai baterai."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 9ae165d..a37eda6 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Vekjarahljóð"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tilkynningarhljóð"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Óþekkt"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Wi-Fi net í boði</item>
-      <item quantity="other">Wi-Fi net í boði</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Opin Wi-Fi net í boði</item>
-      <item quantity="other">Opin Wi-Fi net í boði</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Tengjast opnu Wi-Fi neti"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Tengist við Wi-Fi net"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Tengt við Wi‑Fi net"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Ekki hægt að tengjast Wi-Fi neti"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Ýttu til að sjá öll netkerfi"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Tengjast"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Öll netkerfi"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Leyfa ráðlögð Wi‑Fi net?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> kom með tillögur að netkerfum. Tækið gæti tengst sjálfkrafa."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Leyfa"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nei, takk"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Kveikt verður sjálfkrafa á Wi‑Fi"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Þegar þú ert nálægt vistuðu hágæðaneti"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ekki kveikja aftur"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Sjálfkrafa kveikt á Wi-Fi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Þú ert nálægt vistuðu neti: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Skrá inn á Wi-Fi net"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Skrá inn á net"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tengt"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Tengigeta <xliff:g id="NETWORK_SSID">%1$s</xliff:g> er takmörkuð"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ýttu til að tengjast samt"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Breytingar á stillingum heits reits"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Tíðnisvið heita reitsins hefur breyst."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Þetta tæki styður ekki val þitt fyrir aðeins 5 GHz. Í staðinn mun þetta tæki nota 5 GHz tíðnisvið þegar það er í boði."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Skipt yfir á <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Tækið notar <xliff:g id="NEW_NETWORK">%1$s</xliff:g> þegar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> er ekki með internetaðgang. Gjöld kunna að eiga við."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Skipt úr <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> yfir í <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"óþekkt tegund netkerfis"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ekki var hægt að tengjast Wi-Fi"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leyfa tengingu?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Forritið %1$s vill tengjast Wi-Fi netinu %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Forrit"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ræsa Wi-Fi Direct. Þetta mun slökkva á Wi-Fi biðlara/aðgangsstað."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Ekki var hægt að ræsa Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kveikt er á Wi-Fi Direct"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Ýttu til að fá stillingar"</string>
     <string name="accept" msgid="1645267259272829559">"Samþykkja"</string>
     <string name="decline" msgid="2112225451706137894">"Hafna"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Boðið var sent"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Boð um tengingu"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Frá:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sláðu inn PIN-númerið sem er krafist:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-númer:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Wi-Fi tengingu spjaldtölvunnar verður tímabundið slitið á meðan hún er tengd við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV mun tímabundið aftengjast Wi-Fi á meðan það er tengt við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Síminn mun tímabundið aftengjast Wi-Fi á meðan hann er tengdur við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Setja inn staf"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-skilaboð send"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; er að senda mikinn fjölda SMS-skilaboða. Viltu leyfa þessu forriti að halda áfram að senda skilaboð?"</string>
@@ -1818,8 +1771,10 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Kerfisstjóri uppfærði"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Kerfisstjóri eyddi"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Í lagi"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Rafhlöðusparnaður slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika sem nota mikla orku til að lengja rafhlöðuendingu. "<annotation id="url">"Frekari upplýsingar"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Rafhlöðusparnaður slekkur á eða takmarkar bakgrunnsvirkni, tilteknar myndbrellur og aðra eiginleika sem nota mikla orku til að lengja rafhlöðuendingu."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <string name="data_saver_description" msgid="6015391409098303235">"Gagnasparnaður getur hjálpað til við að draga úr gagnanotkun með því að hindra forrit í að senda eða sækja gögn í bakgrunni. Forrit sem er í notkun getur náð í gögn, en gerir það kannski sjaldnar. Niðurstaðan gæti verið, svo dæmi sé tekið, að myndir séu ekki birtar fyrr en þú ýtir á þær."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Kveikja á gagnasparnaði?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Kveikja"</string>
@@ -2052,4 +2007,23 @@
     </plurals>
     <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 77eafcc..2b780d0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Suoni delle sveglie"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Suoni di notifica"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Sconosciuta"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Reti Wi-Fi disponibili</item>
-      <item quantity="one">Rete Wi-Fi disponibile</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Apri reti Wi-Fi disponibili</item>
-      <item quantity="one">Apri rete Wi-Fi disponibile</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Stabilisci la connessione per aprire la rete Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Connessione alla rete Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Connessione alla rete Wi-Fi stabilita"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Impossibile connettersi alla rete Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tocca per vedere tutte le reti"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Connetti"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Tutte le reti"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vuoi consentire le reti Wi-Fi suggerite?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ha suggerito delle reti. Il dispositivo potrebbe collegarsi automaticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Consenti"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"No, grazie"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Il Wi‑Fi verrà attivato automaticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quando ti trovi nell\'area di una rete salvata di alta qualità"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Non riattivare"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi attivato automaticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ti trovi nell\'area di copertura di una rete salvata: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Accedi a rete Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Accedi alla rete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Connesso"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ha una connettività limitata"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tocca per connettere comunque"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modifiche alle tue impostazioni dell\'hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"La tua banda di hotspot è cambiata."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Questo dispositivo non supporta la tua preferenza esclusiva per 5 GHz. Utilizzerà invece la banda a 5 GHz solo quando è disponibile."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Passato a <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Il dispositivo utilizza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> non ha accesso a Internet. Potrebbero essere applicati costi."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Passato da <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> a <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"tipo di rete sconosciuto"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ha una connessione Internet debole."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Consentire la connessione?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"L\'applicazione %1$s vorrebbe connettersi alla rete Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Un\'applicazione"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Avvio di Wi-Fi Direct non riuscito."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tocca per le impostazioni"</string>
     <string name="accept" msgid="1645267259272829559">"Accetto"</string>
     <string name="decline" msgid="2112225451706137894">"Rifiuto"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invito inviato"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invito a connettersi"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Da:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"A:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Il tablet verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Il dispositivo Android TV verrà scollegato temporaneamente dalla rete Wi-Fi mentre è connesso a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Il telefono verrà momentaneamente scollegato dalla rete Wi-Fi durante il collegamento a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sta inviando molti SMS. Vuoi consentire all\'applicazione di continuare a inviare messaggi?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Risparmio energetico disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità a consumo elevato per prolungare la durata della batteria. "<annotation id="url">"Ulteriori informazioni"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Risparmio energetico disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità a consumo elevato per prolungare la durata della batteria."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 2888a53..dfbf834 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"צלילי התראה"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"צלילי התראה"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"לא ידוע"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="two">‏יש רשתות Wi-Fi זמינות</item>
-      <item quantity="many">‏יש רשתות Wi-Fi זמינות</item>
-      <item quantity="other">‏יש רשתות Wi-Fi זמינות</item>
-      <item quantity="one">‏יש רשת Wi-Fi זמינה</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="two">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
-      <item quantity="many">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
-      <item quantity="other">‏יש רשתות Wi-Fi פתוחות וזמינות</item>
-      <item quantity="one">‏יש רשת Wi-Fi פתוחה וזמינה</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"‏התחברות לרשת Wi‑Fi פתוחה"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"‏התחברות לרשת Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"‏מחובר לרשת Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"‏לא ניתן היה להתחבר לרשת Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"יש להקיש כדי לראות את כל הרשתות"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"התחבר"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"כל הרשתות"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"‏לאפשר הצעות לרשתות Wi-Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"הצעות לרשתות <xliff:g id="NAME">%s</xliff:g>. ייתכן שחיבור המכשיר ייעשה באופן אוטומטי."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"אישור"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"לא תודה"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"‏ה-Wi-Fi יופעל אוטומטית"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"כשתימצאו בקרבת רשת באיכות גבוהה ששמרתם"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"אל תפעיל שוב"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"‏רשת Wi‑Fi הופעלה אוטומטית"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"המיקום הנוכחי שלך הוא בקרבת הרשת השמורה: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏היכנס לרשת Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"היכנס לרשת"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"הרשת מחוברת"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"הקישוריות של <xliff:g id="NETWORK_SSID">%1$s</xliff:g> מוגבלת"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"כדי להתחבר למרות זאת יש להקיש"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"שינויים להגדרות של הנקודה לשיתוף אינטרנט"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"התדר של הנקודה לשיתוף אינטרנט השתנה."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"‏מכשיר זה לא תומך בהעדפות שלך ל-5GHz בלבד. במקום זאת, מכשיר זה ישתמש בתדר 5GHz כשיהיה זמין."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"מעבר אל <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"המכשיר משתמש ברשת <xliff:g id="NEW_NETWORK">%1$s</xliff:g> כשלרשת <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> אין גישה לאינטרנט. עשויים לחול חיובים."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"עבר מרשת <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> לרשת <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"סוג רשת לא מזוהה"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏אין אפשרות להתחבר ל-Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" בעל חיבור גרוע לאינטרנט."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"האם להתיר את החיבור?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏האפליקציה %1$s מנסה להתחבר אל רשת ה-Wi-Fi ‏%2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"אפליקציה"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ישיר"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏הפעל Wi-Fi ישיר. פעולה זו תכבה את הנקודה לשיתוף אינטרנט ב-Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏לא ניתן להפעיל Wi-Fi ישיר"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"‏Wi-Fi ישיר מופעל"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"הקש לקבלת הגדרות"</string>
     <string name="accept" msgid="1645267259272829559">"קבל"</string>
     <string name="decline" msgid="2112225451706137894">"דחה"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ההזמנה נשלחה"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"הזמנה להתחבר"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"מאת:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"אל:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד הגישה הנדרש."</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"קוד גישה:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"‏הטאבלט יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"‏מכשיר ה-Android TV יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"‏הטלפון יתנתק מרשת ה-Wi-Fi באופן זמני בשעה שהוא מחובר אל <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"הוסף תו"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"‏שולח הודעות SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"‏&lt;b&gt; <xliff:g id="APP_NAME">%1$s</xliff:g> &lt;/ b&gt; שולח מספר רב של הודעות SMS. האם ברצונך לאפשר לאפליקציה זו להמשיך לשלוח הודעות?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"\'חיסכון בסוללה\' מכבה או מגביל פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות שצורכות הרבה חשמל, כדי להאריך את חיי הסוללה. "<annotation id="url">"מידע נוסף"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"\'חיסכון בסוללה\' מכבה או מגביל פעילות ברקע, חלק מהאפקטים החזותיים ותכונות אחרות שצורכות הרבה חשמל, כדי להאריך את חיי הסוללה."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 2a2b71b..4776980 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"アラーム音"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"通知音"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"不明"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">複数のWi-Fiネットワークが利用できます</item>
-      <item quantity="one">Wi-Fiネットワークが利用できます</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">複数のWi-Fiオープンネットワークが利用できます</item>
-      <item quantity="one">Wi-Fiオープンネットワークが利用できます</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Wi-Fi オープン ネットワークに接続"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi-Fi ネットワークに接続中"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi-Fi ネットワークに接続しました"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi ネットワークに接続できませんでした"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"すべてのネットワークを表示するにはタップします"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"接続"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"すべてのネットワーク"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Wi‑Fi ネットワーク候補を許可しますか?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> からのネットワーク候補に、デバイスが自動的に接続される可能性があります。"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"許可"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"許可しない"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi は自動的にオンになります"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"高品質の保存済みネットワークの検出時"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"再度オンにしない"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi が自動的に ON になりました"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"保存済みネットワーク「<xliff:g id="NETWORK_SSID">%1$s</xliff:g>」の近くにいます"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fiネットワークにログイン"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ネットワークにログインしてください"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"接続しました"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> の接続が制限されています"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"接続するにはタップしてください"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"アクセス ポイントの設定の変更"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"アクセス ポイントの帯域幅が変更されました。"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"このデバイスは 5 GHz のみという設定に対応していません。ただし、5 GHz 周波数帯が利用できるときには利用します。"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"「<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>」に切り替えました"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"デバイスで「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」によるインターネット接続ができない場合に「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」を使用します。通信料が発生することがあります。"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"「<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>」から「<xliff:g id="NEW_NETWORK">%2$s</xliff:g>」に切り替えました"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明なネットワーク タイプ"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" はインターネット接続に問題があります。"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"接続を許可しますか?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"アプリ%1$sがWi-Fiネットワーク%2$sへの接続を希望しています"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"アプリ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directを開始できませんでした。"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"タップして設定を表示"</string>
     <string name="accept" msgid="1645267259272829559">"同意する"</string>
     <string name="decline" msgid="2112225451706137894">"同意しない"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"招待状を送信しました"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"接続への招待"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"From:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"タブレットが<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が切断されます"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV デバイスが <xliff:g id="DEVICE_NAME">%1$s</xliff:g> に接続されている間は一時的に Wi-Fi 接続が解除されます"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"モバイル デバイスが<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に接続されている間は一時的にWi-Fi接続が解除されます。"</string>
     <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;が大量のSMSメッセージを送信しています。このアプリにこのままメッセージの送信を許可しますか?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"バッテリー セーバーを有効にすると、電池を長持ちさせるようバックグラウンド アクティビティ、一部の視覚効果など、電力消費量の多い機能が制限されます。"<annotation id="url">"詳細"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"バッテリー セーバーを有効にすると、電池を長持ちさせるため、バックグラウンド アクティビティや一部の視覚効果など、電力消費量の多い機能が制限されます。"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 ebc7f2a..7f06b01 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"მაღვიძარას ხმები"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"შეტყობინების ხმები"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"უცნობი"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">ხელმისაწვდომია Wi-Fi ქსელები</item>
-      <item quantity="one">ხელმისაწვდომია Wi-Fi ქსელი</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">ხელმისაწვდომია ღია Wi-Fi ქსელები</item>
-      <item quantity="one">ხელმისაწვდომია ღია Wi-Fi ქსელი</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"დაუკავშირდით ღია Wi‑Fi ქსელს"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"მიმდინარეობს Wi‑Fi ქსელთან დაკავშირება"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi ქსელთან დაკავშირება წარმატებით მოხერხდა"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi ქსელთან დაკავშირება ვერ მოხერხდა"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"შეეხეთ ყველა ქსელის სანახავად"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"დაკავშირება"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ყველა ქსელი"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"გსურთ, დაუშვათ შემოთავაზებული Wi‑Fi ქსელები?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> შემოთავაზებული ქსელები. მოწყობილობა შეიძლება ავტომატურად დაუკავშირდეს."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"დაშვება"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"არა, გმადლობთ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi ავტომატურად ჩაირთვება"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"როცა შენახულ მაღალხარისხიან ქსელებთან ახლოს იმყოფებით"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ხელახლა ნუ ჩართავ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ავტომატურად ჩაირთო"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"თქვენ შენახული ქსელის მახლობლად ხართ: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ქსელთან დაკავშირება"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ქსელში შესვლა"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"დაკავშირებულია"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>-ის კავშირები შეზღუდულია"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"შეეხეთ, თუ მაინც გსურთ დაკავშირება"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"თქვენი უსადენო ქსელის პარამეტრების ცვლილება"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"თქვენი უსადენო ქსელის დიაპაზონი შეიცვალა."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ამ მოწყობილობას არ შეუძლია მხოლოდ 5 გჰც სიხშირეზე მუშაობა. აღნიშნული სიხშირის გამოყენება მოხდება მაშინ, როცა ეს შესაძლებელია."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"ახლა გამოიყენება <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"თუ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ინტერნეტთან კავშირს დაკარგავს, მოწყობილობის მიერ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> იქნება გამოყენებული, რამაც შეიძლება დამატებითი ხარჯები გამოიწვიოს."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"ახლა გამოიყენება <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> (გამოიყენებოდა <xliff:g id="NEW_NETWORK">%2$s</xliff:g>)"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"უცნობი ტიპის ქსელი"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-თან დაკავშირება ვერ მოხერხდა"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ცუდი ინტერნეტ-კავშირი."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"გსურთ კავშირის დაშვება?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"განაცხადს %1$s სურს დაუკავშირდეს Wifi ქსელს %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"აპლიკაცია"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ჩართეთ Wi-Fi Direct. ეს გამოიწვევს Wi-Fi კლიენტისა/უსადენო ქსელის გამორთვას."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ვერ მოხერხდა Wi-Fi Direct-ის გაშვება."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ჩართულია"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"შეეხეთ პარამეტრების სანახავად"</string>
     <string name="accept" msgid="1645267259272829559">"მიღება"</string>
     <string name="decline" msgid="2112225451706137894">"უარყოფა"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"მოწვევა გაგზავნილია"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"მოწვევა დასაკავშირებლად"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"გამგზავნი:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"მიმღები:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"შეიყვანეთ საჭირო PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"პინ-კოდი:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ტაბლეტი დროებით გაითიშება Wi-Fi-დან, სანამ მიერთებულია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ზე"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"თქვენი Android TV მოწყობილობა დროებით გაითიშება Wi-Fi-დან, სანამ ის <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან იქნება დაკავშირებული"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ტელეფონი დროებით გაითიშება Wi-Fi-დან, სანამ მიერთებულია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ზე"</string>
     <string name="select_character" msgid="3365550120617701745">"სიმბოლოს ჩასმა"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS შეტყობინებები იგზავნება"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;აგზავნის დიდი რაოდენობის SMS შეტყობინებებს. გსურთ, მისცეთ ამ აპს უფლება გააგრძელოს შეტყობინეების დაგზავნა?"</string>
@@ -1817,8 +1771,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგი გამორთავს ან შეზღუდავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს და სხვა ფუნქციებს, რომლებზეც დიდი ენერგია იხარჯება. "<annotation id="url">"შეიტყვეთ მეტი"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ბატარეის მუშაობის გახანგრძლივების მიზნით, ბატარეის დამზოგი გამორთავს ან შეზღუდავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს და სხვა ფუნქციებს, რომლებზეც დიდი ენერგია იხარჯება."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 281db7a..65da546 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Дабыл сигналдары"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Хабарландыру сигналдары"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Белгісіз"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi желілері қол жетімді</item>
-      <item quantity="one">Wi-Fi желісі қол жетімді</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Ашық Wi-Fi желілері қол жетімді</item>
-      <item quantity="one">Ашық Wi-Fi желісі қол жетімді</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Ашық Wi‑Fi желісіне қосылу"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi желісіне қосылуда"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi желісіне қосылды"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi желісіне қосылмады"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Барлық желілерді көру үшін түртіңіз"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Қосылу"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Барлық желілер"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Ұсынылған Wi‑Fi желілеріне рұқсат беру керек пе?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ұсынған желілер. Құрылғы автоматты түрде қосылуы мүмкін."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Рұқсат беру"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Жоқ, рақмет"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi автоматты түрде қосылады"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Сақталған жоғары сапалы желіге жақын болғанда"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Қайта қоспау"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi автоматты түрде қосылды"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Сақталған желінің маңайындасыз: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi желісіне кіру"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Желіге кіру"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Жалғанды"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> желісінің қосылу мүмкіндігі шектеулі."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Бәрібір жалғау үшін түртіңіз."</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Хотспот параметрлеріне өзгерістер енгізілді"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Хотспот жолағы өзгертілді."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Бұл құрылғы тек 5 ГГц жиілікте жұмыс істей алмайды. Бұл жиілік мүмкін болған жағдайда ғана қолданылады."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> желісіне ауысты"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Құрылғы <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> желісінде интернетпен байланыс жоғалған жағдайда <xliff:g id="NEW_NETWORK">%1$s</xliff:g> желісін пайдаланады. Деректер ақысы алынуы мүмкін."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> желісінен <xliff:g id="NEW_NETWORK">%2$s</xliff:g> желісіне ауысты"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"желі түрі белгісіз"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi желісіне қосыла алмады"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Қосылуға рұқсат ету керек пе?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s қолданбасы %2$s Wi-Fi желісіне қосылғысы келеді"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Қолданба"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi тікелей"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Тікелей байланысын бастау. Бұл Wi-Fi клиент/хот-спотты өшіреді."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Тікелей байланысын қоса алмады."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Тікелей Wi-Fi қосулы"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Параметрлер үшін түртіңіз"</string>
     <string name="accept" msgid="1645267259272829559">"Қабылдау"</string>
     <string name="decline" msgid="2112225451706137894">"Бас тарту"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Шақыру жіберілді"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Жалғау үшін шақыру"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Кімнен:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кімге:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Өтінілген PIN кодты теру:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Планшет <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына қосылғанша Wi-Fi байланысынан уақытша ажыратылады"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына қосулы тұрғанда, Android TV құрылғысы Wi-Fi желісінен уақытша ажырайды."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысына жалғанып тұрғанда телефон уақытша Wi-Fi байланысынан ажыратылады"</string>
     <string name="select_character" msgid="3365550120617701745">"Таңба енгізу"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS хабарларын жіберу"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; қолданбасы көп SMS хабарын жіберуде. Осы қолданбаның хабарларды жіберуді жалғастыруын қалайсыз ба?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Battery Saver функциясы батарея қуатын үнемдеу үшін фондық әрекеттерді, кейбір көрнекі әсерлерді және басқа да қуатты көп пайдаланатын мүмкіндіктерді өшіреді немесе шектейді. "<annotation id="url">"Толығырақ"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Battery Saver функциясы батарея қуатын үнемдеу үшін фондық әрекеттерді, кейбір көрнекі әсерлерді және басқа да қуатты көп пайдаланатын мүмкіндіктерді өшіреді немесе шектейді."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 532e3c7..32b3ee1 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1246,30 +1246,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"សំឡេងម៉ោងរោទិ៍"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"សំឡេងជូនដំណឹង"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"មិន​ស្គាល់"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">មានបណ្តាញ Wi-Fi</item>
-      <item quantity="one">មានបណ្តាញ Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
-      <item quantity="one">បើកបណ្តាញ Wi-Fi ដែលមាន</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ភ្ជាប់ទៅបណ្តាញ Wi‑Fi ចំហ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"កំពុង​ភ្ជាប់​ទៅ​បណ្តាញ Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"បានភ្ជាប់ទៅបណ្តាញ Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"មិនអាចភ្ជាប់ទៅបណ្តាញ Wi‑Fi បានទេ"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ចុចដើម្បីមើលបណ្តាញទាំងអស់"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"ភ្ជាប់"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"បណ្ដាញ​ទាំងអស់"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"អនុញ្ញាតឱ្យ​ភ្ជាប់​បណ្ដាញ Wi‑Fi ដែលបាន​ណែនាំ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"បណ្ដាញ​ដែលបាន​ណែនាំ​របស់ <xliff:g id="NAME">%s</xliff:g> ។ ឧបករណ៍​អាច​ភ្ជាប់​ដោយស្វ័យប្រវត្តិ។"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"អនុញ្ញាត"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ទេ អរគុណ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi នឹង​បើក​ដោយ​ស្វ័យប្រវត្តិ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"នៅពេល​ដែល​អ្នក​នៅ​ជិត​បណ្តាញ​គុណភាព​ខ្ពស់​ដែល​បាន​រក្សាទុក"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"កុំ​បើក​ឡើង​វិញ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi បានបើកដោយស្វ័យប្រវត្តិ"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"អ្នកនៅជិត​បណ្តាញ​ដែលបានរក្សាទុក៖ <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ចូល​បណ្ដាញ​វ៉ាយហ្វាយ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ចូលទៅបណ្តាញ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1282,9 +1258,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"បានភ្ជាប់"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> មានការតភ្ជាប់​មានកម្រិត"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"មិន​អី​ទេ ចុច​​ភ្ជាប់​ចុះ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ប្ដូរ​ទៅ​ការ​កំណត់​ហតស្ប៉ត​របស់អ្នក"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"រលកសញ្ញាហតស្ប៉តរបស់​អ្នកបាន​ផ្លាស់ប្ដូរ។"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ឧបករណ៍​នេះ​មិន​អាច​ប្រើចំណូល​ចិត្ត​របស់អ្នកសម្រាប់តែ 5GHz ទេ។ ផ្ទុយ​មកវិញ ឧបករណ៍​នេះ​នឹង​ប្រើរលកសញ្ញា​ 5GHz នៅពេល​ដែលអាច​ប្រើបាន។"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"បានប្តូរទៅ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"ឧបករណ៍​ប្រើ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> នៅ​ពេល​ដែល <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> មិនមាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត។ អាច​គិតថ្លៃ​លើការ​ប្រើប្រាស់​ទិន្នន័យ។"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"បានប្តូរពី <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ទៅ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1296,27 +1269,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ប្រភេទបណ្តាញមិនស្គាល់"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"មិន​​អាច​តភ្ជាប់​វ៉ាយហ្វាយ"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត​​មិន​ល្អ។"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"អនុញ្ញាត​ភ្ជាប់?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"កម្មវិធី %1$s ចង់ភ្ជាប់ទៅបណ្តាញ Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"កម្មវិធី"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"វ៉ាយហ្វាយ​ផ្ទាល់"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ចាប់ផ្ដើម​វ៉ាយហ្វាយ​ផ្ទាល់។ វា​នឹង​បិទ​វ៉ាយហ្វាយ​ហតស្ពត។"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"មិន​អាច​ចាប់ផ្ដើម​វ៉ាយហ្វា​ដោយ​ផ្ទាល់។"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"បើក​​វ៉ាយហ្វាយ​ផ្ទាល់"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ប៉ះសម្រាប់ការកំណត់"</string>
     <string name="accept" msgid="1645267259272829559">"ទទួល"</string>
     <string name="decline" msgid="2112225451706137894">"បដិសេធ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"បា​ន​ផ្ញើ​លិខិត​អញ្ជើញ"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"អញ្ជើញ​ឲ្យ​ភ្ជាប់"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ពី៖"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ទៅ៖"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"បញ្ចូល​កូដ PIN ដែល​ទាមទារ៖"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"កូដ PIN ៖"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"កុំព្យូទ័រ​បន្ទះ​នឹង​ផ្ដាច់​ជា​បណ្ដោះអាសន្ន​ពី​វ៉ាយហ្វាយ ខណៈ​ដែល​វា​ភ្ជាប់​ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ឧបករណ៍ Android TV របស់អ្នកនឹង​ផ្ដាច់ពី Wi-Fi ជាបណ្តោះអាសន្ន នៅពេល​ឧបករណ៍នេះភ្ជាប់ជាមួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ទូរស័ព្ទ​នឹង​​ផ្ដាច់​ពី​វ៉ាយហ្វាយ​ខណៈ​ដែល​វា​ត្រូវ​បាន​តភ្ជាប់​ទៅ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"បញ្ចូល​តួអក្សរ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"ផ្ញើ​សារ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; កំពុង​ផ្ញើ​សារ​ SMS មួយ​ចំនួន​ធំ។ តើ​អ្នក​ចង់​ឲ្យ​​កម្មវិធី​នេះ​បន្ត​ផ្ញើ​សារ?"</string>
@@ -1819,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"កម្មវិធី​សន្សំ​ថ្មនឹងបិទ ឬ​រឹតបន្តឹង​សកម្មភាព​ផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារប្រើប្រាស់​ថាមពលច្រើន​ផ្សេងទៀត ដើម្បី​បង្កើន​​ថាមពល​ថ្មឱ្យប្រើបានយូរ​ជាងមុន។ "<annotation id="url">"ស្វែងយល់បន្ថែម"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"កម្មវិធី​សន្សំ​ថ្មនឹងបិទ ឬ​រឹតបន្តឹង​សកម្មភាព​ផ្ទៃខាងក្រោយ ឥទ្ធិពល​ជារូបភាពមួយចំនួន និងមុខងារប្រើប្រាស់​ថាមពលច្រើនផ្សេងទៀត ដើម្បី​បង្កើន​​ថាមពល​ថ្មឱ្យប្រើបានយូរ​ជាងមុន។"</string>
+    <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>
@@ -2053,4 +2007,23 @@
     </plurals>
     <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 3fb6766..0fab683 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"ಅಲಾರಮ್ ಧ್ವನಿಗಳು"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ಅಧಿಸೂಚನೆ ಧ್ವನಿಗಳು"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ಅಪರಿಚಿತ"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
-      <item quantity="other">ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
-      <item quantity="other">ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗಳು ಲಭ್ಯವಿವೆ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ಮುಕ್ತ ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಿ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗುತ್ತಿದೆ"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ವೈ-ಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ಎಲ್ಲಾ ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ನೋಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"ಸಂಪರ್ಕಿಸಿ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ಎಲ್ಲಾ ನೆಟ್‌ವರ್ಕ್‌ಗಳು"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"ಸೂಚಿಸಿರುವ ನೆಟ್‌ವರ್ಕ್‌ಗಳನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ಸೂಚಿಸಿರುವ ನೆಟ್‌ವರ್ಕ್‌ಗಳು. ಸಾಧನಗಳು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸಂಪರ್ಕಗೊಳ್ಳಬಹುದು."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ಅನುಮತಿಸಿ"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ಬೇಡ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ವೈ‑ಫೈ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಆಗುತ್ತದೆ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ನೀವು ಉಳಿಸಿದ ಅಧಿಕ ಗುಣಮಟ್ಟದ ನೆಟ್‌ವರ್ಕ್‌ ಸಮೀಪದಲ್ಲಿದ್ದಾಗ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ಮತ್ತೆ ಆನ್ ಮಾಡಲು ಹಿಂತಿರುಗಬೇಡಿ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ವೈ-ಫೈ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಆನ್ ಆಗಿದೆ"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ನೀವು ಉಳಿಸಿದ ನೆಟ್‌ವರ್ಕ್‌ನ ಸಮೀಪವಿರುವಿರಿ: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ವೈ-ಫೈ ನೆಟ್‍ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ಸೀಮಿತ ಸಂಪರ್ಕ ಕಲ್ಪಿಸುವಿಕೆಯನ್ನು ಹೊಂದಿದೆ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ಹೇಗಾದರೂ ಸಂಪರ್ಕಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ನಿಮ್ಮ ಹಾಟ್‌ಸ್ಪಾಟ್‌ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಬದಲಾವಣೆಗಳು"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ನಿಮ್ಮ ಹಾಟ್‌ಸ್ಪಾಟ್‌ ಬ್ಯಾಂಡ್ ಬದಲಾಗಿದೆ."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ಈ ಸಾಧನವು 5GHz ಗೆ ಮಾತ್ರ ನಿಮ್ಮ ಆದ್ಯತೆಯನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ. ಬದಲಿಗೆ, ಈ ಸಾಧನವು 5GHz ಬ್ಯಾಂಡ್ ಅನ್ನು ಲಭ್ಯವಿರುವಾಗ ಬಳಸುತ್ತದೆ."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ ಹೊಂದಿಲ್ಲದಿರುವಾಗ, ಸಾಧನವು <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ಬಳಸುತ್ತದೆ. ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ರಿಂದ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ಗೆ ಬದಲಾಯಿಸಲಾಗಿದೆ"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ಅಪರಿಚಿತ ನೆಟ್‌ವರ್ಕ್ ಪ್ರಕಾರ"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ವೈ-ಫೈ ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ಸಂಪರ್ಕವನ್ನು ಅನುಮತಿಸುವುದೇ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s ವೈಫೈ ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು %1$s ಅಪ್ಲಿಕೇಶನ್‌ ಬಯಸುತ್ತದೆ"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ಅಪ್ಲಿಕೇಶನ್"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ವೈ-ಫೈ ಡೈರೆಕ್ಟ್"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ವೈ-ಫೈ ಡೈರೆಕ್ಟ್ ಪ್ರಾರಂಭಿಸಿ. ಇದು ವೈ-ಫೈ ಕ್ಲೈಂಟ್‌/ಹಾಟ್‌ಸ್ಪಾಟ್ ಅನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ವೈ-ಫೈ ಡೈರೆಕ್ಟ್ ಪ್ರಾರಂಭಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ವೈ-ಫೈ ಡೈರೆಕ್ಟ್ ಆನ್ ಆಗಿದೆ"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
     <string name="accept" msgid="1645267259272829559">"ಸ್ವೀಕರಿಸು"</string>
     <string name="decline" msgid="2112225451706137894">"ನಿರಾಕರಿಸಿ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ಆಹ್ವಾನವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ಸಂಪರ್ಕಗೊಳ್ಳಲು ಆಹ್ವಾನ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ಇಂದ:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ಗೆ:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ಅಗತ್ಯವಿರುವ ಪಿನ್‌ ಟೈಪ್ ಮಾಡಿ:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ಪಿನ್‌:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ಟ್ಯಾಬ್ಲೆಟ್ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ ಅದನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ವೈ-ಫೈ ನಿಂದ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತದೆ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ನಿಮ್ಮ Android TV ಸಾಧನವು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ, ವೈ-ಫೈ ನಿಂದ ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಂಪರ್ಕ ಕಡಿದುಕೊಳ್ಳುತ್ತದೆ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ಫೋನ್ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಗೊಂಡಿರುವಾಗ ವೈ-ಫೈ ನಿಂದ ಅದು ತಾತ್ಕಾಲಿಕವಾಗಿ ಸಂಪರ್ಕ ಕಡಿತಗೊಳ್ಳುತ್ತದೆ"</string>
     <string name="select_character" msgid="3365550120617701745">"ಅಕ್ಷರವನ್ನು ಸೇರಿಸಿ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸುತ್ತಿದೆ. ಸಂದೇಶಗಳ ಕಳುಹಿಸುವಿಕೆಯನ್ನು ಮುಂದುವರಿಸುವಂತೆ ಈ ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸಲು ನೀವು ಬಯಸುವಿರಾ?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ಹೆಚ್ಚಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್ ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು ಇತರ ಅಧಿಕ ಬ್ಯಾಟರಿ ಬಳಸುವ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ. "<annotation id="url">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯನ್ನು ಹೆಚ್ಚಿಸಲು, ಬ್ಯಾಟರಿ ಸೇವರ್ ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ದೃಶ್ಯಾತ್ಮಕ ಎಫೆಕ್ಟ್‌ಗಳು ಮತ್ತು ಇತರ ಅಧಿಕ ಬ್ಯಾಟರಿ ಬಳಸುವ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆಫ್ ಮಾಡುತ್ತದೆ ಅಥವಾ ನಿರ್ಬಂಧಿಸುತ್ತದೆ."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 acc6e95..f42a928 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"알람 소리"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"알림 사운드"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"알 수 없음"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi 네트워크 사용 가능</item>
-      <item quantity="one">Wi-Fi 네트워크 사용 가능</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">개방형 Wi-Fi 네트워크 사용 가능</item>
-      <item quantity="one">개방형 Wi-Fi 네트워크 사용 가능</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"공개 Wi‑Fi 네트워크에 연결"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi-Fi 네트워크에 연결 중"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi 네트워크에 연결됨"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi 네트워크에 연결할 수 없음"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"모든 네트워크를 보려면 탭하세요."</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"연결"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"모든 네트워크"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"제안된 Wi‑Fi 네트워크를 허용하시겠습니까?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g>에서 네트워크를 제안했습니다. 기기가 자동으로 연결될 수 있습니다."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"허용"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"허용 안함"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi가 자동으로 사용 설정됨"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"저장된 고품질 네트워크가 가까이 있는 경우"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"다시 사용 설정하지 않음"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi가 자동으로 사용 설정됨"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"주변에 저장된 네트워크(<xliff:g id="NETWORK_SSID">%1$s</xliff:g>)가 있습니다"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi 네트워크에 로그인"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"네트워크에 로그인"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"연결되었습니다."</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>에서 연결을 제한했습니다."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"계속 연결하려면 탭하세요."</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"핫스팟 설정 변경"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"핫스팟 대역이 변경되었습니다."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"이 기기에서는 5GHz 전용 환경설정이 지원되지 않습니다. 대신 가능할 때만 기기에서 5GHz 대역이 사용됩니다."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>(으)로 전환"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>(으)로 인터넷에 연결할 수 없는 경우 기기에서 <xliff:g id="NEW_NETWORK">%1$s</xliff:g>이(가) 사용됩니다. 요금이 부과될 수 있습니다."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>에서 <xliff:g id="NEW_NETWORK">%2$s</xliff:g>(으)로 전환"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"알 수 없는 네트워크 유형"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 인터넷 연결 상태가 좋지 않습니다."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"연결을 허용하시겠습니까?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s 애플리케이션에서 %2$s Wi-Fi 네트워크에 연결하려고 합니다."</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"앱"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct를 시작하지 못했습니다."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"탭하여 설정 보기"</string>
     <string name="accept" msgid="1645267259272829559">"동의"</string>
     <string name="decline" msgid="2112225451706137894">"거부"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"초대장을 보냈습니다."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"연결하도록 초대"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"보낸사람:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"수신:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 태블릿의 Wi-Fi 연결이 해제됩니다."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 Android TV 기기의 Wi-Fi 연결이 일시적으로 해제됩니다."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에 연결되어 있는 동안 일시적으로 휴대전화의 Wi-Fi 연결이 해제됩니다."</string>
     <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;이(가) SMS 메시지를 대량으로 보내고 있습니다. 해당 앱이 메시지를 계속 보내도록 하시겠습니까?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"절전 모드에서는 백그라운드 활동을 사용 중지하거나 제한합니다. 배터리 수명을 늘리기 위해 일부 시각 효과 및 기타 배터리 소모가 큰 기능이 제한됩니다. "<annotation id="url">"자세히 알아보기"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"절전 모드에서는 배터리 수명을 늘리기 위해 백그라운드 활동, 일부 시각 효과 및 기타 배터리 소모가 큰 기능을 사용 중지하거나 제한합니다."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 db54c42..82064b2 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ойготкучтун добуштары"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Эскертменин добуштары"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Белгисиз"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi тармагы жеткиликтүү</item>
-      <item quantity="one">Wi-Fi тармагы жеткиликтүү</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Ачык Wi-Fi тармагы жеткиликтүү</item>
-      <item quantity="one">Ачык Wi-Fi тармагы жеткиликтүү</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Ачык Wi‑Fi тармагына туташуу"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi тармагына туташууда"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ачык Wi‑Fi тармагына туташты"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi-Fi тармагына туташпай калды"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Бардык тармактарды көрүү үчүн басыңыз"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Туташуу"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Бардык тармактар"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Сунушталган Wi‑Fi тармактарына туташасызбы?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> сунуштаган тармактар. Түзмөк автоматтык түрдө туташышы мүмкүн."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Уруксат берүү"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Жок, рахмат"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi автоматтык түрдө күйөт"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Байланыш сигналы күчтүү тармактарга жакындаганда"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Өзү кайра күйбөйт"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi автоматтык түрдө күйгүзүлдү"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Сакталган тармактын жанындасыз: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi түйүнүнө кирүү"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Тармакка кирүү"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Туташты"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> байланышы чектелген"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Баары бир туташуу үчүн таптаңыз"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Байланыш түйүнүңүздүн жөндөөлөрү өзгөрүлдү"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Байланыш түйүнүңүздүн жыштыгы өзгөрдү."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Бул түзмөк 5ГГцти гана колдонуу жөндөөсүн колдоого албайт. Анын ордуна, бул түзмөк 5ГГц жыштыгын ал жеткиликтүү болгондо колдонот."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> тармагына которуштурулду"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> тармагы Интернетке туташпай турганда, түзмөгүңүз <xliff:g id="NEW_NETWORK">%1$s</xliff:g> тармагын колдонот. Акы алынышы мүмкүн."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> дегенден <xliff:g id="NEW_NETWORK">%2$s</xliff:g> тармагына которуштурулду"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"белгисиз тармак түрү"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi менен туташуу түзүлбөдү"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Туташууга уруксатпы?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s колдонмосу %2$s Wifi тармагына туташкысы келет"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Колдонмо"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Дайректи иштетүү. Бул Wi-Fi клиентти/хотспотту өчүрөт."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct иштетилген жок."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct иштөөдө"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Жөндөөлөрдү ачуу үчүн таптап коюңуз"</string>
     <string name="accept" msgid="1645267259272829559">"Кабыл алуу"</string>
     <string name="decline" msgid="2112225451706137894">"Баш тартуу"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Чакыруу жөнөтүлдү"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Туташууга чакыруу"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Жөнөтүүчү:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Алуучу:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Талап кылынган PIN\'ди териңиз:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Планшет <xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышып турганда, Wi-Fi\'дан убактылуу ажыратылат"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүнө туташып турганда убактылуу Wi-Fi\'дан ажыратылат"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефон <xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышып турганда, Wi-Fi\'дан убактылуу ажыратылат"</string>
     <string name="select_character" msgid="3365550120617701745">"Символ киргизүү"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS билдирүүлөр жөнөтүлүүдө"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; көп SMS билдирүүлөрдү жөнөтүп жатат. Бул колдонмо билдирүүлөрдү жөнөтө берсинби?"</string>
@@ -1819,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Батареяны үнөмдөгүч функциясы фондогу аракеттерди, айрым визуалдык эффекттерди жана башка батареяны көп сарптаган функцияларды өчүрүп же чектеп, батареянын кубатынын мөөнөтүн узартат. "<annotation id="url">"Кеңири маалымат"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Батареяны үнөмдөгүч функциясы фондогу аракеттерди, айрым визуалдык эффекттерди жана башка батареяны көп сарптаган функцияларды өчүрүп же чектеп, батареянын кубатынын мөөнөтүн узартат."</string>
+    <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>
@@ -2053,4 +2006,23 @@
     </plurals>
     <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 6ef4cca..3aa786e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm sounds"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Notification sounds"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ບໍ່ຮູ້ຈັກ"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
-      <item quantity="one">ເຄືອຂ່າຍ Wi-Fi ທີ່ມີໃຫ້</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
-      <item quantity="one">ເປີດເຄືອຂ່າຍ Wi-Fi  ທີ່ມີໃຫ້</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍ Wi‑Fi ແບບເປີດ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ກຳລັງເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍ Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍ Wi‑Fi ແລ້ວ"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ບໍ່ສາມາດເຊື່ອມຕໍ່ຫາເຄືອຂ່າຍ Wi‑Fi ໄດ້"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ແຕະເພື່ອເບິ່ງເຄືອຂ່າຍທັງໝົດ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"ເຊື່ອມ​ຕໍ່"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ເຄືອຂ່າຍທັງໝົດ"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"ອະນຸຍາດເຄືອຂ່າຍ Wi‑Fi ທີ່ແນະນຳບໍ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"ເຄືອຂ່າຍ <xliff:g id="NAME">%s</xliff:g> ທີ່ແນະນຳ. ອຸປະກອນອາດເຊື່ອມຕໍ່ເອງໂດຍອັດຕະໂນມັດ."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ອະນຸຍາດ"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ບໍ່, ຂອບໃຈ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ຈະມີການເປີດໃຊ້ Wi‑Fi ອັດຕະໂນມັດ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ເມື່ອທ່ານຢູ່ໃກ້ເຄືອຂ່າຍຄຸນນະພາບສູງທີ່ບັນທຶກໄວ້"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ບໍ່ຕ້ອງເປີດໃຊ້ຄືນໃໝ່"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ເປີດໃຊ້ Wi‑Fi ອັດຕະໂນມັດແລ້ວ"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ທ່ານຢູ່ໃກ້ເຄືອຂ່າຍທີ່ບັນທຶກໄວ້: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ເຂົ້າສູ່ລະບົບເຄືອຂ່າຍ Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ລົງຊື່ເຂົ້າເຄືອຂ່າຍ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ມີການເຊື່ອມຕໍ່ທີ່ຈຳກັດ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ແຕະເພື່ອຢືນຢັນການເຊື່ອມຕໍ່"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ການປ່ຽນແປງການຕັ້ງຄ່າຮັອດສະປອດຂອງທ່ານ"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ຄື້ນຄວາມຖີ່ຮັອດສະປອດຂອງທ່ານປ່ຽນແປງແລ້ວ."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ອຸປະກອນນີ້ບໍ່ຮອງຮັບການຕັ້ງຄ່າຂອງທ່ານສຳລັບ 5GHz ເທົ່ານັ້ນ. ແຕ່ວ່າອຸປະກອນນີ້ຈະໃຊ້ຄື້ນຄວາມຖີ່ 5GHz ເມື່ອສາມາດໃຊ້ໄດ້."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"ສະຫຼັບໄປໃຊ້ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ແລ້ວ"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"ອຸປະກອນຈະໃຊ້ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ເມື່ອ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ. ອາດມີການຮຽກເກັບຄ່າບໍລິການ."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"ສະຫຼັບຈາກ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ໄປໃຊ້ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ແລ້ວ"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ບໍ່ຮູ້ຈັກປະເພດເຄືອຂ່າຍ"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ບໍ່ສາມາດເຊື່ອມຕໍ່ Wi-Fi ໄດ້"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດທີ່ຊ້າ."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"​ອະ​ນຸ​ຍາດ​ການ​ເຊື່ອມ​ຕໍ່ຫຼື​ບໍ່?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ %1$s ຢາກ​ຈະ​ເຊື່ອມ​ຕໍ່​ກັບ​ເຄືອ​ຂ່າຍ Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"​ແອັບ​ພລິ​ເຄ​ຊັນ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ເລີ່ມ Wi-Fi Direct. ນີ້ຈະເປັນການປິດ Wi-Fi client/hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ບໍ່ສາມາດເລີ່ມ Wi-Fi Direct ໄດ້."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ເປີດໃຊ້ Wi-Fi Direct ແລ້ວ"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ແຕະເພື່ອເບິ່ງການຕັ້ງຄ່າ"</string>
     <string name="accept" msgid="1645267259272829559">"ຍອມຮັບ"</string>
     <string name="decline" msgid="2112225451706137894">"ປະຕິເສດ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ການ​ເຊື້ອ​ເຊີນ​ຖືກສົ່ງໄປແລ້ວ"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ການເຊີນຊວນເພື່ອເຊື່ອມຕໍ່"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ຈາກ:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ຈາກ:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ພິມລະຫັດ PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ແທັບເລັດຈະຖືກຕັດການເຊື່ອມຕໍ່ຈາກ Wi-Fi ເປັນການຊົ່ວຄາວ ໃນຂະນະທີ່ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຢູ່."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ອຸປະກອນ Android TV ຂອງທ່ານຈະຕັດການເຊື່ອມຕໍ່ຈາກ Wi-Fi ເປັນການຊົ່ວຄາວໃນລະຫວ່າງທີ່ມັນເຊື່ອມຕໍ່ຫາ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ໂທລະສັບຈະຖືກຢຸດການເຊື່ອມຕໍ່ຊົ່ວຄາວຈາກ Wi-Fi ໃນຂະນະທີ່ມັນເຊື່ອມຕໍ່ກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"ໃສ່ໂຕອັກສອນ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"ກຳລັງສົ່ງຂໍ້ຄວາມ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ກຳລັງສົ່ງຂໍ້ຄວາມ SMS ຈຳນວນຫຼາຍ. ທ່ານຕ້ອງການອະນຸຍາດໃຫ້ແອັບຯສືບຕໍ່ການສົ່ງຂໍ້ຄວາມບໍ່?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ຕົວປະຢັດແບັດເຕີຣີຈະປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດທີ່ໃຊ້ພະລັງງານຫຼາຍອື່ນໆເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ. "<annotation id="url">"ສຶກສາເພີ່ມເຕີມ"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ຕົວປະຢັດແບັດເຕີຣີຈະປິດ ຫຼື ຈຳກັດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບບາງຢ່າງ ແລະ ຄຸນສົມບັດທີ່ໃຊ້ພະລັງງານຫຼາຍອື່ນໆເພື່ອຂະຫຍາຍອາຍຸແບັດເຕີຣີ."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 f2c17c3..d4d19f4 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Įspėjimų garsai"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Pranešimų garsai"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nežinoma"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Pasiekiami „Wi-Fi“ tinklai</item>
-      <item quantity="few">Pasiekiami „Wi-Fi“ tinklai</item>
-      <item quantity="many">Pasiekiami „Wi-Fi“ tinklai</item>
-      <item quantity="other">Pasiekiami „Wi-Fi“ tinklai</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
-      <item quantity="few">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
-      <item quantity="many">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
-      <item quantity="other">Pasiekiami atvirieji „Wi-Fi“ tinklai</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Prisijunkite prie atviro „Wi‑Fi“ tinklo"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Jungiamasi prie „Wi-Fi“ tinklo"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Prisijungta prie „Wi-Fi“ tinklo"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nepavyko prisijungti prie „Wi‑Fi“ tinklo"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Palieskite, jei norite matyti visus tinklus"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Prisijungti"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Visi tinklai"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Leisti siūlomus „Wi‑Fi“ tinklus?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"„<xliff:g id="NAME">%s</xliff:g>“ siūlomi tinklai. Įrenginys gali prisijungti automatiškai."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Leisti"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, ačiū"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"„Wi‑Fi“ bus įjungtas automatiškai"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kai būsite netoli išsaugoto aukštos kokybės tinklo"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Neįjunkite vėl"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"„Wi‑Fi“ įjungtas automatiškai"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Esate netoli išsaugoto tinklo: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prisijungti prie „Wi-Fi“ tinklo"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prisijungti prie tinklo"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Prisijungta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"„<xliff:g id="NETWORK_SSID">%1$s</xliff:g>“ ryšys apribotas"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Palieskite, jei vis tiek norite prisijungti"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Viešosios interneto prieigos taško nustatymų pakeitimai"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Viešosios prieigos taško dažnio juosta pasikeitė."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Šiame įrenginyje nepalaikoma tik 5 GHz nuostata. Vietoj to šiame įrenginyje bus naudojama 5 GHz dažnio juosta, kai bus pasiekiama."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Perjungta į tinklą <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Įrenginyje naudojamas kitas tinklas (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>), kai dabartiniame tinkle (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nėra interneto ryšio. Gali būti taikomi mokesčiai."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Perjungta iš tinklo <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> į tinklą <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nežinomas tinklo tipas"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" turi prastą interneto ryšį."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Leisti prisijungti?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programa „%1$s“ nori prisijungti prie „Wi-Fi“ tinklo „%2$s“"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programa"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nepavyko paleisti „Wi-Fi Direct“."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Palieskite, kad būtų rodomi nustatymai"</string>
     <string name="accept" msgid="1645267259272829559">"Sutikti"</string>
     <string name="decline" msgid="2112225451706137894">"Atmesti"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pakvietimas išsiųstas"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pakvietimas prisijungti"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Nuo:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Skirta:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Planšetinis kompiuteris bus laikinai atjungtas nuo „Wi-Fi“, kol jis prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"„Android TV“ įrenginys bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonas bus laikinai atjungtas nuo „Wi-Fi“, kol bus prijungtas prie „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“"</string>
     <string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Naudojant &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; siunčiama daug SMS pranešimų. Ar norite leisti šiai programai toliau siųsti pranešimus?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Akumuliatoriaus tausojimo priemonė išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas daug energijos eikvojančias funkcijas, kad akumuliatorius veiktų ilgiau. "<annotation id="url">"Sužinokite daugiau"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Akumuliatoriaus tausojimo priemonė išjungia arba apriboja veiklą fone, kai kuriuos vaizdinius efektus ir kitas daug energijos eikvojančias funkcijas, kad akumuliatorius veiktų ilgiau."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 be8d5d1..89a98dd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1264,32 +1264,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Modinātāja signāla skaņas"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Paziņojumu skaņas"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nezināms"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="zero">Pieejami Wi-Fi tīkli</item>
-      <item quantity="one">Pieejami Wi-Fi tīkli</item>
-      <item quantity="other">Pieejami Wi-Fi tīkli</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="zero">Ir pieejami atvērti Wi-Fi tīkli</item>
-      <item quantity="one">Ir pieejami atvērti Wi-Fi tīkli</item>
-      <item quantity="other">Ir pieejami atvērti Wi-Fi tīkli</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Savienojuma izveide ar atvērtu Wi-Fi tīklu"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Savienojuma izveide ar Wi-Fi tīklu"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ir izveidots savienojums ar Wi-Fi tīklu"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nevarēja izveidot savienojumu ar Wi‑Fi tīklu"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Pieskarieties, lai skatītu visus tīklus"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Izveidot savienojumu"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Visi tīkli"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vai atļaut ieteiktos Wi‑Fi tīklus?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Lietotnes <xliff:g id="NAME">%s</xliff:g> ieteiktie tīkli. Ierīcē var tikt automātiski izveidots savienojums."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Atļaut"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nē, paldies"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi tiks automātiski ieslēgts"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kad atrodaties saglabāta augstas kvalitātes tīkla tuvumā"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Neieslēgt atkārtoti"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi tika ieslēgts automātiski"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Jūs atrodaties saglabāta tīkla tuvumā: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>."</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Pierakstieties Wi-Fi tīklā"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Pierakstīšanās tīklā"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1302,9 +1276,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Izveidots savienojums"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Tīklā <xliff:g id="NETWORK_SSID">%1$s</xliff:g> ir ierobežota savienojamība"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Lai tik un tā izveidotu savienojumu, pieskarieties"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Izmaiņas tīklāja iestatījumos"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ir mainīts tīklāja joslas platums."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Šajā ierīcē netiek atbalstīta jūsu preference par tikai 5 GHz joslu. 5 GHz josla ierīcē tiks izmantota, kad tā būs pieejama."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Pārslēdzās uz tīklu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Kad vienā tīklā (<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>) nav piekļuves internetam, ierīcē tiek izmantots cits tīkls (<xliff:g id="NEW_NETWORK">%1$s</xliff:g>). Var tikt piemērota maksa."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Pārslēdzās no tīkla <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> uz tīklu <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,27 +1287,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nezināms tīkla veids"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ir slikts interneta savienojums."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vai atļaut savienojumu?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Lietotne %1$s vēlas izveidot savienojumu ar Wi-Fi tīklu %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Lietojumprogramma"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nevarēja palaist programmu Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Pieskarieties, lai skatītu iestatījumus."</string>
     <string name="accept" msgid="1645267259272829559">"Piekrist"</string>
     <string name="decline" msgid="2112225451706137894">"Noraidīt"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Ielūgums ir nosūtīts."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Ielūgums izveidot savienojumu"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"No:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kam:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Planšetdators tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV ierīce tiks īslaicīgi atvienota no Wi-Fi tīkla, kamēr ir izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Tālrunis tiks īslaicīgi atvienots no Wi-Fi tīkla, kamēr būs izveidots savienojums ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Lietotne &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sūta daudz īsziņu. Vai vēlaties, lai šī lietotne turpinātu sūtīt ziņojumus?"</string>
@@ -1842,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Akumulatora jaudas taupīšanas režīmā tiek izslēgtas vai ierobežotas fona darbības, daži vizuālie efekti un citas lieljaudas funkcijas, lai palielinātu akumulatora darbības ilgumu. "<annotation id="url">"Uzzināt vairāk"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Akumulatora jaudas taupīšanas režīmā tiek izslēgtas vai ierobežotas fona darbības, daži vizuālie efekti un citas lieljaudas funkcijas, lai palielinātu akumulatora darbības ilgumu."</string>
+    <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>
@@ -2087,4 +2039,23 @@
     </plurals>
     <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 ea9a6b4..4396c08 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци за аларм"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци за известување"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Непозната"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Wi-Fi мрежи се достапни</item>
-      <item quantity="other">Wi-Fi мрежи се достапни</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Отворени Wi-Fi мрежи се достапни</item>
-      <item quantity="other">Отворени Wi-Fi мрежи се достапни</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Поврзете се на отворена Wi‑Fi-мрежа"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Поврзување со Wi-Fi мрежа"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Се поврзавте на Wi‑Fi-мрежа"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не можеше да се поврзе на Wi‑Fi-мрежа"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Допрете за да ги видите сите мрежи"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Поврзете се"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Сите мрежи"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Да се дозволат предложените Wi‑Fi мрежи?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Предложени мрежи од <xliff:g id="NAME">%s</xliff:g>. Уредот може да се поврзе автоматски."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Дозволи"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Не, фала"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi ќе се вклучи автоматски"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Кога сте во близина на зачувана мрежа со висок квалитет"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не вклучувај повторно"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi се вклучи автоматски"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Близу сте до зачувана мрежа: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Најавете се на мрежа на Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Најавете се на мрежа"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Поврзано"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничена поврзливост"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Допрете за да се поврзете и покрај тоа"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промени на поставките за точка на пристап"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Појасот за точка на пристап е променет."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Уредов не ги поддржува вашите поставки за само 5 GHz. Наместо тоа, ќе го користи појасот од 5 GHz кога е достапен."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Префрлено на <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Уредот користи <xliff:g id="NEW_NETWORK">%1$s</xliff:g> кога <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема пристап до интернет. Може да се наплатат трошоци."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Префрлено од <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мрежа"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можеше да се поврзе со Wi-Fi"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволете поврзување?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликацијата %1$s сака да се поврзе со Wifi-мрежата %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Започни Wi-Fi Direct. Ова ќе го исклучи Wi-Fi клиентот/хточката на пристап."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не можеше да се стартува Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е вклучена"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Допрете за поставки"</string>
     <string name="accept" msgid="1645267259272829559">"Прифати"</string>
     <string name="decline" msgid="2112225451706137894">"Одбиј"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Поканата е испратена"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Покана да се поврзе"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Од:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"До:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Внеси го бараниот PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблетот привремено ќе се исклучи од Wi-Fi, додека да се приклучи на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Привремено ќе се прекине врската на вашиот уред Android TV со Wi-Fi додека е поврзан со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефонот привремено ќе се исклучи од Wi-Fi додека е приклучен на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Вметни знак"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Испраќање SMS пораки"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; испраќа голем број SMS пораки. Дали сакате да дозволите оваа апликација да продолжи со испраќање пораки?"</string>
@@ -1820,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Штедачот на батерија ги исклучува или ограничува активноста во заднина, некои визуелни ефекти и други функции со голема потрошувачка на енергија за да се продолжи траењето на батеријата. "<annotation id="url">"Дознајте повеќе"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Штедачот на батерија ги исклучува или ограничува активноста во заднина, некои визуелни ефекти и други функции со голема потрошувачка на енергија за да се продолжи траењето на батеријата."</string>
+    <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>
@@ -2054,4 +2007,23 @@
     </plurals>
     <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 5250df5..0b33971 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"അലാറം ശബ്ദങ്ങൾ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"അറിയിപ്പ് ശബ്ദങ്ങൾ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"അറിഞ്ഞുകൂടാത്തത്"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">വൈഫൈ നെറ്റ്‌വർക്കുകൾ ലഭ്യമാണ്</item>
-      <item quantity="one">വൈഫൈ നെറ്റ്‌വർക്ക് ലഭ്യമാണ്</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">ലഭ്യമായ വൈഫൈ നെറ്റ്‌വർക്കുകൾ തുറക്കുക</item>
-      <item quantity="one">ലഭ്യമായ വൈഫൈ നെറ്റ്‌വർക്ക് തുറക്കുക</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ലഭ്യമായ വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റുചെയ്യുക"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റ് ചെയ്യുന്നു"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് കണക്റ്റു‌ചെയ്‌‌തു"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"വൈ-ഫൈ നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റുചെയ്യാനായില്ല"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"എല്ലാ നെറ്റ്‌വർക്കുകളും കാണാൻ ടാപ്പുചെയ്യുക"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"കണക്റ്റുചെയ്യുക"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"എല്ലാ നെറ്റ്‌വർക്കുകളും"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"നിർദ്ദേശിച്ച വെെഫെെ നെറ്റ്‌വർക്കുകൾ അനുവദിക്കണോ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> നിർദ്ദേശിച്ച നെറ്റ്‌വർക്കുകൾ. ഉപകരണം സ്വയമേവ കണക്‌റ്റ് ചെയ്‌തേക്കാം."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"അനുവദിക്കുക"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"വേണ്ട"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"വൈഫൈ സ്വമേധയാ ഓണാകും"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"നിങ്ങൾ ഉയർന്ന നിലവാരമുള്ള സംരക്ഷിക്കപ്പെട്ട നെറ്റ്‌വർക്കിനരികിലെത്തുമ്പോൾ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"തിരികെ ഓണാക്കരുത്"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"വൈഫൈ സ്വമേധയാ ഓണായി"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"നിങ്ങൾ സംരക്ഷിച്ചിട്ടുള്ള ഒരു നെറ്റ്‌വർക്കിന് സമീപമാണ്: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"വൈഫൈ നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"നെറ്റ്‌വർക്കിലേക്ക് സൈൻ ഇൻ ചെയ്യുക"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"കണക്‌റ്റ് ചെയ്‌തു"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> എന്നതിന് പരിമിതമായ കണക്റ്റിവിറ്റി ഉണ്ട്"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ഏതുവിധേനയും കണക്‌റ്റ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ക്രമീകരണത്തിൽ വരുത്തിയ മാറ്റങ്ങൾ"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"നിങ്ങളുടെ ഹോട്ട്‌സ്‌പോട്ട് ബാൻഡ് മാറി."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"നിങ്ങളുടെ മുൻഗണനയനുസരിച്ചുള്ള, 5GHz മാത്രം എന്നത് ഈ ഉപകരണം പിന്തുണയ്ക്കുന്നില്ല. പകരം, 5GHz ബാൻഡ് ലഭ്യമാകുമ്പോൾ അത് ഉപയോഗിക്കും."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> എന്നതിലേക്ക് മാറി"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>-ന് ഇന്റർനെറ്റ് ആക്‌സസ് ഇല്ലാത്തപ്പോൾ ഉപകരണം <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ഉപയോഗിക്കുന്നു. നിരക്കുകൾ ബാധകമായേക്കാം."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> നെറ്റ്‌വർക്കിൽ നിന്ന് <xliff:g id="NEW_NETWORK">%2$s</xliff:g> നെറ്റ്‌വർക്കിലേക്ക് മാറി"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"തിരിച്ചറിയാനാകാത്ത ഒരു നെറ്റ്‌വർക്ക് തരം"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-ലേക്ക് കണക്‌റ്റുചെയ്യാൻ കഴിഞ്ഞില്ല"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"കണക്ഷൻ അനുവദിക്കണോ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"അപ്ലിക്കേഷൻ %1$s Wifi നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റുചെയ്യാൻ താൽപ്പര്യപ്പെടുന്നു %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ഒരു അപ്ലിക്കേഷൻ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"വൈഫൈ ഡയറക്‌ട്"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"വൈഫൈ ഡയറക്റ്റ് ആരംഭിക്കുക. ഇത് വൈഫൈ ക്ലയന്റ്/ഹോട്ട്‌സ്‌പോട്ട് ഓഫാക്കും."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"വൈഫൈ ഡയറക്റ്റ് ആരംഭിക്കാനായില്ല."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"വൈഫൈ ഡയറക്‌ട് ഓണാണ്"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ക്രമീകരണത്തിന് ടാപ്പുചെയ്യുക"</string>
     <string name="accept" msgid="1645267259272829559">"അംഗീകരിക്കുക"</string>
     <string name="decline" msgid="2112225451706137894">"നിരസിക്കുക"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ക്ഷണം അയച്ചു"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"കണക്റ്റുചെയ്യാനുള്ള ക്ഷണം"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"അയച്ചത്:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ടു:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ആവശ്യമായ പിൻ ടൈപ്പുചെയ്യുക:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"പിൻ:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ടാബ്‌ലെറ്റ് <xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിൽ കണക്റ്റുചെയ്‌തിരിക്കുമ്പോൾ അത് താൽക്കാലികമായി Wi-Fi-യിൽ നിന്നും വിച്ഛേദിക്കപ്പെടും."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"നിങ്ങളുടെ Android ടിവി <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ഉപകരണവുമായി കണക്‌റ്റ് ചെയ്‌തിരിക്കുമ്പോൾ അത് താൽക്കാലികമായി വൈഫൈയിൽ നിന്ന് വിച്‌ഛേദിക്കും"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുമ്പോൾ ഫോൺ Wi-Fi-യിൽ നിന്ന് താൽക്കാലികമായി വിച്ഛേദിക്കും"</string>
     <string name="select_character" msgid="3365550120617701745">"പ്രതീകം ചേർക്കുക"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS സന്ദേശങ്ങൾ അയയ്‌ക്കുന്നു"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; വളരെയധികം SMS സന്ദേശങ്ങൾ അയയ്‌ക്കുന്നു. സന്ദേശങ്ങൾ തുടർന്നും അയയ്‌ക്കാൻ ഈ അപ്ലിക്കേഷനെ അനുവദിക്കണോ?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ബാറ്ററി ലൈഫ് വികസിപ്പിക്കാൻ പശ്ചാത്തല ആക്‌റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്‌റ്റുകൾ, മറ്റ് ഹൈ പവർ ഫീച്ചറുകൾ എന്നിവയെ ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും. "<annotation id="url">"കൂടുതലറിയുക"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ബാറ്ററി ലൈഫ് വികസിപ്പിക്കാൻ പശ്ചാത്തല ആക്‌റ്റിവിറ്റി, ചില വിഷ്വൽ ഇഫക്‌റ്റുകൾ, മറ്റ് ഹൈ പവർ ഫീച്ചറുകൾ എന്നിവയെ ബാറ്ററി ലാഭിക്കൽ ഓഫാക്കുകയോ നിയന്ത്രിക്കുകയോ ചെയ്യും."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 9a4ffae..990a4d0 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Сэрүүлгийн ая"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Мэдэгдлийн дуу"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Тодорхойгүй"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi сүлжээ ашиглах боломжтой</item>
-      <item quantity="one">Wi-Fi сүлжээ ашиглах боломжтой</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
-      <item quantity="one">Нээлттэй Wi-Fi сүлжээ ашиглах боломжтой</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Нээлттэй Wi‑Fi сүлжээнд холбогдох"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi сүлжээнд холбогдож байна"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi сүлжээнд холбогдлоо"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi сүлжээнд холбогдож чадсангүй"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Бүх сүлжээг харахын тулд товшино уу"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Холбогдох"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Бүх сүлжээ"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Санал болгосон Wi‑Fi сүлжээг зөвшөөрөх үү?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> сүлжээ санал болголоо. Төхөөрөмж автоматаар холбогдож магадгүй."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Зөвшөөрөх"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Үгүй, баярлалаа"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi автоматаар асна"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Таныг хадгалсан, өндөр чанартай сүлжээний ойролцоо байх үед"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Буцааж асаахгүй"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi-г автоматаар асаасан"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Та дараах хадгалсан сүлжээтэй ойрхон байна: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi сүлжээнд нэвтэрнэ үү"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Сүлжээнд нэвтэрнэ үү"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Холбогдсон"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> зарим үйлчилгээнд хандах боломжгүй байна"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ямар ч тохиолдолд холбогдохын тулд товших"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Таны сүлжээний цэгийн тохиргооны өөрчлөлт"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Таны сүлжээний цэгийн зурвасыг өөрчилсөн."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Энэ төхөөрөмж таны \"зөвхөн 5Гц\" гэсэн давуу сонголтыг дэмждэггүй. Үүний оронд энэ төхөөрөмж 5Гц зурвасыг боломжтой үед нь ашиглах болно."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> руу шилжүүлсэн"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> интернет холболтгүй үед төхөөрөмж <xliff:g id="NEW_NETWORK">%1$s</xliff:g>-г ашигладаг. Төлбөр гарч болзошгүй."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>-с <xliff:g id="NEW_NETWORK">%2$s</xliff:g> руу шилжүүлсэн"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"сүлжээний тодорхойгүй төрөл"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi-д холбогдож чадсангүй"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" Интернет холболт муу байна."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Холболтыг зөвшөөрөх үү?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Програм %1$s нь Wifi сүлжээ %2$s-тай холбох хүсэлтэй байна"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Аппликейшн"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Шууд"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Шуудыг эхлүүлнэ үү. Энэ нь Wi-Fi клиент/холболтын цэг унтраана."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Шуудыг эхлүүлж чадсангүй."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Шууд асав"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Тохиргоо хийхийн тулд товшино уу"</string>
     <string name="accept" msgid="1645267259272829559">"Зөвшөөрөх"</string>
     <string name="decline" msgid="2112225451706137894">"Татгалзах"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Урилга илгээгдсэн"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Холбох урилга"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Хэнээс:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Хэнд:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Шаардлагатай PIN-г бичнэ үү:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблет <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тэй холбогдох үедээ түр зуур Wi-Fi-с салах болно."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Таны Android ТВ төхөөрөмж <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-д холбогдсон үед Wi-Fi-с түр хугацаанд сална"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Утас <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай холбогдох үедээ түр зуур Wi-Fi-с салах болно."</string>
     <string name="select_character" msgid="3365550120617701745">"Тэмдэгт оруулах"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS мессеж илгээж байна"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; их хэмжээний SMS мессежийг илгээж байна. Та энэ апп-д үргэлжлүүлэн мессеж илгээхийг зөвшөөрөх үү?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Батарей хэмнэгч батарейны ажиллах хугацааг сунгахын тулд арын үйл ажиллагаа, зарим визуал эффект болон бусад өндөр эрчим хүч зарцуулдаг онцлогийг унтрааж эсвэл хязгаарладаг. "<annotation id="url">"Нэмэлт мэдээлэл авах"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Батарей хэмнэгч батарейны ажиллах хугацааг сунгахын тулд арын үйл ажиллагаа, зарим визуал эффект болон бусад өндөр эрчим хүч зарцуулдаг онцлогийг унтрааж эсвэл хязгаарладаг."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 39f614a..edc89a4 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -218,7 +218,7 @@
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"तुमचा फोन बंद होईल."</string>
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"तुम्ही बंद करू इच्छिता?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोडमध्ये रीबूट करा"</string>
-    <string name="reboot_safemode_confirm" msgid="55293944502784668">"तुम्ही सुरक्षित मोडमध्ये रीबूट करू इच्छिता? हे तुम्ही इंस्टॉल केलेले सर्व तृतीय पक्ष अॅप्लिकेशन अक्षम करेल. तुम्ही पुन्हा रीबूट करता तेव्हा ते पुनर्संचयित केले जातील."</string>
+    <string name="reboot_safemode_confirm" msgid="55293944502784668">"तुम्ही सुरक्षित मोडमध्ये रीबूट करू इच्छिता? हे तुम्ही इंस्टॉल केलेले सर्व तृतीय पक्ष ॲप्लिकेशन अक्षम करेल. तुम्ही पुन्हा रीबूट करता तेव्हा ते पुनर्संचयित केले जातील."</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"अलीकडील"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"अलीकडील कोणतेही अ‍ॅप्स नाहीत."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"टॅबलेट पर्याय"</string>
@@ -269,9 +269,9 @@
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"रीटेल डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्‍शन"</string>
     <string name="notification_channel_heavy_weight_app" msgid="6218742927792852607">"APP चालत आहे"</string>
-    <string name="notification_channel_foreground_service" msgid="3931987440602669158">"बॅटरी लवकर संपवणारी अॅप्‍स"</string>
+    <string name="notification_channel_foreground_service" msgid="3931987440602669158">"बॅटरी लवकर संपवणारी ॲप्‍स"</string>
     <string name="foreground_service_app_in_background" msgid="1060198778219731292">"<xliff:g id="APP_NAME">%1$s</xliff:g> बॅटरी वापरत आहे"</string>
-    <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> अॅप्‍स बॅटरी वापरत आहेत"</string>
+    <string name="foreground_service_apps_in_background" msgid="7175032677643332242">"<xliff:g id="NUMBER">%1$d</xliff:g> ॲप्‍स बॅटरी वापरत आहेत"</string>
     <string name="foreground_service_tap_for_details" msgid="372046743534354644">"बॅटरी आणि डेटा वापराच्‍या तपशीलांसाठी टॅप करा"</string>
     <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
@@ -339,13 +339,13 @@
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"केले जाणारे कॉल पुन्हा मार्गस्थ करा"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"कॉल केला जात असताना कॉलला भिन्न नंबरवर पुनर्निर्देशित करण्‍याच्‍या किंवा संपूर्ण कॉल रद्द करण्‍याच्‍या पर्यायासह डायल केला जाणारा नंबर पाहण्‍याची अ‍ॅपला अनुमती देते"</string>
     <string name="permlab_answerPhoneCalls" msgid="4077162841226223337">"फोन कॉलचे उत्तर द्या"</string>
-    <string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"येणार्‍या फोन कॉलचे उत्तर देण्यास अॅपला अनुमती देते."</string>
+    <string name="permdesc_answerPhoneCalls" msgid="2901889867993572266">"येणार्‍या फोन कॉलचे उत्तर देण्यास ॲपला अनुमती देते."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"मजकूर मेसेज मिळवा (SMS)"</string>
     <string name="permdesc_receiveSms" msgid="6424387754228766939">"SMS मेसेज प्राप्त करण्याची आणि त्यावर प्रक्रिया करण्याची अ‍ॅप ला अनुमती देते. म्हणजेच अ‍ॅप आपल्या डीव्हाइसवर पाठविलेले मेसेज तुम्हाला न दर्शवता त्यांचे परीक्षण करू किंवा ते हटवू शकतो."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"मजकूर मेसेज मिळवा (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"MMS मेसेज प्राप्त करण्यास आणि त्यावर प्रक्रिया करण्यास अ‍ॅप ला अनुमती देते. म्हणजेच अ‍ॅप आपल्या डिव्हाइसवर पाठविलेले मेसेज तुम्हाला न दर्शवता त्यांचे परीक्षण करू किंवा ते हटवू शकतो."</string>
     <string name="permlab_bindCellBroadcastService" msgid="4468585041824555604">"सेल प्रसारण मेसेज फॉरवर्ड करा"</string>
-    <string name="permdesc_bindCellBroadcastService" msgid="9073440260695196089">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी अॅपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अ‍ॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
+    <string name="permdesc_bindCellBroadcastService" msgid="9073440260695196089">"सेल प्रसारण मेसेज मिळाल्यानंतर ते फॉरवर्ड करण्यासाठी ॲपला सेल प्रसारण मॉड्यूलमध्ये प्रतिबद्ध करण्याची अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थीतींची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरित केल्या जातात. दुर्भावनापूर्ण अ‍ॅप्स आणीबाणी सेल प्रसारण मिळवतात तेव्हा ती तुमच्या डिव्हाइसच्या परफॉर्मन्समध्ये किंवा कामामध्ये कदाचित व्यत्यय आणू शकतात."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"सेल प्रसारण मेसेज वाचा"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"आपल्या डिव्हाइसद्वारे प्राप्त केलेले सेल प्रसारण मेसेज वाचण्यासाठी अ‍ॅप ला अनुमती देते. काही स्थानांमध्ये तुम्हाला आणीबाणीच्या परिस्थितीची चेतावणी देण्यासाठी सेल प्रसारण सूचना वितरीत केल्या जातात. आणीबाणी सेल प्रसारण प्राप्त होते तेव्हा आपल्या डिव्हाइसच्या कार्यप्रदर्शनात किंवा कार्यात दुर्भावनापूर्ण अ‍ॅप्स व्यत्यय आणू शकतात."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"सदस्यता घेतलेली फीड वाचा"</string>
@@ -361,7 +361,7 @@
     <string name="permlab_getTasks" msgid="6466095396623933906">"चालणारे अ‍ॅप्स पुनर्प्राप्त करा"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"सध्या आणि अलीकडे चालणार्‍या कार्यांविषयी माहिती पुनर्प्राप्त करण्यासाठी अ‍ॅप ला अनुमती देते. हे डिव्हाइसवर कोणते अ‍ॅप्लिकेशन वापरले जात आहेत त्याविषयी माहिती शोधण्यासाठी अ‍ॅप ला अनुमती देऊ शकतात."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="7918181259098220004">"प्रोफाईल आणि डिव्हाइस मालक व्यवस्थापित करा"</string>
-    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"प्रोफाईल मालक आणि डिव्हाइस मालक सेट करण्याची अॅप्सना अनुमती द्या."</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"प्रोफाईल मालक आणि डिव्हाइस मालक सेट करण्याची ॲप्सना अनुमती द्या."</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"चालणारे अ‍ॅप्स पुनर्क्रमित करा"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"समोर आणि पार्श्वभूमीवर कार्ये हलविण्यासाठी अ‍ॅप ला अनुमती देते. अ‍ॅप हे आपल्या इनपुटशिवाय करू शकतो."</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"कार मोड सुरू करा"</string>
@@ -376,7 +376,7 @@
     <string name="permdesc_useDataInBackground" msgid="6049514223791806027">"हे अ‍ॅप पार्श्वभूमीत डेटा वापरू शकते. हे डेटाचा वापर वाढवू शकते."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"अ‍ॅप नेहमी चालवा"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"अ‍ॅप ला मेमरीमध्ये कायम असलेले त्याचे स्वतःचे भाग बनविण्यास अनुमती देते. हे टॅबलेट धीमा करून अन्य अ‍ॅप्सवर उपलब्ध असलेल्या मेमरीवर मर्यादा घालू शकते."</string>
-    <string name="permdesc_persistentActivity" product="tv" msgid="47072473951071734">"अॅपला मेमरीमध्ये कायम असलेले त्याचे स्वतःचे भाग बनवण्याची अनुमती देते. हे Android TV डिव्हाइस धीमे करून अन्य अॅप्सवर उपलब्ध असलेल्या मेमरीवर मर्यादा घालू शकते."</string>
+    <string name="permdesc_persistentActivity" product="tv" msgid="47072473951071734">"ॲपला मेमरीमध्ये कायम असलेले त्याचे स्वतःचे भाग बनवण्याची अनुमती देते. हे Android TV डिव्हाइस धीमे करून अन्य ॲप्सवर उपलब्ध असलेल्या मेमरीवर मर्यादा घालू शकते."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"अ‍ॅप ला मेमरीमध्ये कायम असलेले त्याचे स्वतःचे भाग बनविण्यास अनुमती देते. हे फोन धीमा करून अन्य अ‍ॅप्सवर उपलब्ध असलेल्या मेमरीवर मर्यादा घालू शकते."</string>
     <string name="permlab_foregroundService" msgid="3310786367649133115">"पृष्‍ठभाग सेवा रन करा"</string>
     <string name="permdesc_foregroundService" msgid="6471634326171344622">"अ‍ॅपला पृष्‍ठभाग सेवा वापरण्याची अनुमती देते."</string>
@@ -386,35 +386,35 @@
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"सिस्टीमचा सेटिंग्ज डेटा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स आपल्या सिस्टीमचे कॉन्फिगरेशन दूषित करू शकतात."</string>
     <string name="permlab_receiveBootCompleted" msgid="5312965565987800025">"सुरूवातीस चालवा"</string>
     <string name="permdesc_receiveBootCompleted" product="tablet" msgid="7390304664116880704">"जसे सिस्टम बूट करणे समाप्त करते तसे अ‍ॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे टॅबलेट प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर टॅबलेटला धीमे करण्यास अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_receiveBootCompleted" product="tv" msgid="6725487837446317527">"सिस्टम बूट होणे संपल्यावर अॅपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती अॅपला देते."</string>
+    <string name="permdesc_receiveBootCompleted" product="tv" msgid="6725487837446317527">"सिस्टम बूट होणे संपल्यावर ॲपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती ॲपला देते."</string>
     <string name="permdesc_receiveBootCompleted" product="default" msgid="513950589102617504">"जसे सिस्टम बूट करणे समाप्त करते तसे अ‍ॅप ला स्वतः प्रारंभ करण्यास अनुमती देते. यामुळे फोन प्रारंभ करण्यास वेळ लागू शकतो आणि नेहमी चालू राहून एकंदर फोनला धीमे करण्यास अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_broadcastSticky" msgid="7919126372606881614">"रोचक प्रसारण पाठवा"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="7749760494399915651">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो टॅब्लेटला धीमा किंवा अस्थिर करू शकतो."</string>
-    <string name="permdesc_broadcastSticky" product="tv" msgid="5029460344724532288">"चिकट प्रसारणे पाठविण्यासाठी अॅपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धीमा किंवा अस्थिर करू शकतो."</string>
+    <string name="permdesc_broadcastSticky" product="tv" msgid="5029460344724532288">"चिकट प्रसारणे पाठविण्यासाठी ॲपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धीमा किंवा अस्थिर करू शकतो."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो फोनला धीमा किंवा अस्थिर करू शकतो."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"तुमचे संपर्क वाचा"</string>
     <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"तुम्ही कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी तुमचा संपर्क डेटा सेव्ह करण्याची अ‍ॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अ‍ॅप्स आपल्या माहितीशिवाय संपर्क डेटा शेअर करू शकतात."</string>
-    <string name="permdesc_readContacts" product="tv" msgid="3890061004911027912">"तुम्ही केलेले कॉल, केलेले ईमेल किंवा विशिष्‍ट संपर्कांसह अन्य मार्गांनी केलेले कम्युनिकेशन यांची वारंवारता, यासह तुमच्या Android TV डिव्‍हाइसवर स्टोअर केलेल्‍या तुमच्या संपर्कांविषयीचा डेटा वाचण्याची अॅपला अनुमती देते. ही परवानगी अ‍ॅप्सना तुमचा संपर्क डेटा सेव्ह करण्याची अनुमती देते आणि ही दुर्भावनापूर्ण अ‍ॅप्स तुम्हाला न कळवता संपर्क डेटा शेअर करू शकतात."</string>
+    <string name="permdesc_readContacts" product="tv" msgid="3890061004911027912">"तुम्ही केलेले कॉल, केलेले ईमेल किंवा विशिष्‍ट संपर्कांसह अन्य मार्गांनी केलेले कम्युनिकेशन यांची वारंवारता, यासह तुमच्या Android TV डिव्‍हाइसवर स्टोअर केलेल्‍या तुमच्या संपर्कांविषयीचा डेटा वाचण्याची ॲपला अनुमती देते. ही परवानगी अ‍ॅप्सना तुमचा संपर्क डेटा सेव्ह करण्याची अनुमती देते आणि ही दुर्भावनापूर्ण अ‍ॅप्स तुम्हाला न कळवता संपर्क डेटा शेअर करू शकतात."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"तुम्ही कॉल केलेल्या, ईमेल केलेल्या किंवा विशिष्ट लोकांशी अन्य मार्गांनी संवाद प्रस्थापित केलेल्या लोकांच्या फ्रिक्वेन्सीसह, आपल्या फोनवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा वाचण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी तुमचा संपर्क डेटा सेव्ह करण्याची अ‍ॅप्स ला अनुमती देते आणि दुर्भावनापूर्ण अ‍ॅप्स आपल्या माहितीशिवाय संपर्क डेटा शेअर करू शकतात."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"तुमचे संपर्क सुधारित करा"</string>
     <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"तुम्ही विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या टॅब्लेटवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_writeContacts" product="tv" msgid="307929337692573341">"तुम्ही विशिष्ट संपर्कांशी कॉल, ईमेल किंवा इतर मार्गांनी संवाद प्रस्थापित केल्याची वारंवारता यांच्या समावेशासह, तुमच्या Android TV वर स्टोअर केलेल्या तुमच्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अॅपला अनुमती देते. ही परवानगी अॅपला संपर्क डेटा हटविण्यासाठी अनुमती देते."</string>
+    <string name="permdesc_writeContacts" product="tv" msgid="307929337692573341">"तुम्ही विशिष्ट संपर्कांशी कॉल, ईमेल किंवा इतर मार्गांनी संवाद प्रस्थापित केल्याची वारंवारता यांच्या समावेशासह, तुमच्या Android TV वर स्टोअर केलेल्या तुमच्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी ॲपला अनुमती देते. ही परवानगी ॲपला संपर्क डेटा हटविण्यासाठी अनुमती देते."</string>
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"तुम्ही विशिष्ट संपर्कांशी अन्य मार्गांनी कॉल केलेल्या, ईमेल केलेल्या किंवा संवाद प्रस्थापित केलेल्या फ्रिक्वेन्सीसह, आपल्या फोनवर स्टोअर केलेल्या आपल्या संपर्कांविषयीचा डेटा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. ही परवानगी संपर्क डेटा हटविण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"कॉल लॉग वाचा"</string>
     <string name="permdesc_readCallLog" msgid="3204122446463552146">"हा अ‍ॅप तुमचा कॉल इतिहास वाचू शकता."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"कॉल लॉग लिहा"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, आपल्या टॅब्लेटचा कॉल लॉग सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="7939219462637746280">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, तुमच्या Android TV डिव्हाइसचा कॉल लॉग सुधारित करण्यासाठी अॅपला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="7939219462637746280">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, तुमच्या Android TV डिव्हाइसचा कॉल लॉग सुधारित करण्यासाठी ॲपला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"येणार्‍या आणि केल्या जाणार्‍या कॉलविषयीच्या डेटासह, आपल्या फोनचा कॉल लॉग सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमचा कॉल लॉग मिटवण्यासाठी किंवा सुधारित करण्यासाठी याचा वापर करू शकतात."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"शरीर सेंसर (हृदय गती मॉनिटरसारखे) अ‍ॅक्सेस करा"</string>
-    <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"हृदय गती सारख्या, आपल्या शारीरिक स्थितीचे नियंत्रण करणार्‍या सेन्सरवरून डेटामध्ये प्रवेश करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"हृदय गती सारख्या, आपल्या शारीरिक स्थितीचे नियंत्रण करणार्‍या सेन्सरवरून डेटामध्ये प्रवेश करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_readCalendar" msgid="6716116972752441641">"कॅलेंडर इव्हेंट आणि तपशील वाचा"</string>
     <string name="permdesc_readCalendar" product="tablet" msgid="4993979255403945892">"हा अ‍ॅप आपल्या टॅब्लेटवर स्टोअर केलेले सर्व कॅलेंडर इव्हेंट वाचू आणि शेअर करू शकतो किंवा तुमचा कॅलेंडर डेटा सेव्ह करू शकतो."</string>
-    <string name="permdesc_readCalendar" product="tv" msgid="1066881547471014386">"हे अॅप तुमच्या Android TV डिव्हाइसवर स्टोअर केलेले सर्व कॅलेंडर इव्हेंट वाचू आणि शेअर करू शकतो किंवा तुमचा कॅलेंडर डेटा सेव्ह करू शकतो."</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="1066881547471014386">"हे ॲप तुमच्या Android TV डिव्हाइसवर स्टोअर केलेले सर्व कॅलेंडर इव्हेंट वाचू आणि शेअर करू शकतो किंवा तुमचा कॅलेंडर डेटा सेव्ह करू शकतो."</string>
     <string name="permdesc_readCalendar" product="default" msgid="4373978642145196715">"हा अ‍ॅप आपल्या फोनवर स्टोअर केलेले सर्व कॅलेंडर इव्हेंट वाचू आणि शेअर करू शकतो किंवा तुमचा कॅलेंडर डेटा सेव्ह करू शकतो."</string>
     <string name="permlab_writeCalendar" msgid="8438874755193825647">"कॅलेंडर इव्हेंट जोडा किंवा बदला आणि मालकाला न कळवता अतिथींना ईमेल पाठवा"</string>
     <string name="permdesc_writeCalendar" product="tablet" msgid="1675270619903625982">"हा अ‍ॅप आपल्या टॅब्लेटवर कॅलेंडर इव्हेंट जोडू, काढू किंवा बदलू शकतो. हा अ‍ॅप कॅलेंडर मालकांकडून येत आहेत असे वाटणारे मेसेज पाठवू किंवा त्यांच्या मालकांना सूचित केल्याशिवाय इव्हेंट बदलू शकतो."</string>
-    <string name="permdesc_writeCalendar" product="tv" msgid="3127658465046261646">"हे अॅप तुमच्या Android TV डिव्हाइसवर कॅलेंडर इव्हेंट जोडू, काढू किंवा बदलू शकतो. हे अ‍ॅप कॅलेंडर मालकांकडून येत आहेत असे वाटणारे मेसेज पाठवू किंवा त्यांच्या मालकांना सूचित केल्याशिवाय इव्हेंट बदलू शकतो."</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="3127658465046261646">"हे ॲप तुमच्या Android TV डिव्हाइसवर कॅलेंडर इव्हेंट जोडू, काढू किंवा बदलू शकतो. हे अ‍ॅप कॅलेंडर मालकांकडून येत आहेत असे वाटणारे मेसेज पाठवू किंवा त्यांच्या मालकांना सूचित केल्याशिवाय इव्हेंट बदलू शकतो."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="7592791790516943173">"हा अ‍ॅप आपल्या फोनवर कॅलेंडर इव्हेंट जोडू, काढू किंवा बदलू शकतो. हा अ‍ॅप कॅलेंडर मालकांकडून येत आहेत असे वाटणारे मेसेज पाठवू किंवा त्यांच्या मालकांना सूचित केल्याशिवाय इव्हेंट बदलू शकतो."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"अतिरिक्त स्थान प्रदाता आदेश अ‍ॅक्सेस करा"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"अ‍ॅपला अतिरिक्त स्‍थान प्रदाता आदेशावर प्रवेश करण्‍याची अनुमती देते. हे कदाचित अ‍ॅपला GPS किंवा इतर स्‍थान स्रोत च्या ऑपरेशनमध्‍ये हस्तक्षेप करण्‍याची अनुमती देऊ शकते."</string>
@@ -422,7 +422,7 @@
     <string name="permdesc_accessFineLocation" msgid="3520508381065331098">"हे अ‍ॅप फक्त फोरग्राउंडमध्ये असतानाच तुमचे अचूक स्थान मिळवू शकते. या स्थान सेवा सुरू करणे आणि त्या वापरण्यासाठी अ‍ॅपसाठी तुमच्या फोनवर उपलब्ध करणे आवश्यक आहे, यामुळे बॅटरी वापर वाढू शकतो."</string>
     <string name="permlab_accessCoarseLocation" msgid="3707180371693213469">"फक्त फोरग्राउंडमध्ये अंदाजे स्थान (नेटवर्क आधारित) अ‍ॅक्सेस करा"</string>
     <string name="permdesc_accessCoarseLocation" product="tablet" msgid="8594719010575779120">"हे अ‍ॅप फक्त फोरग्राउंडमध्ये असतानाच, सेल टॉवर आणि वाय-फाय नेटवर्क सारख्या नेटवर्क स्रोतवर आधारित तुमचे स्थान मिळवू शकते. त्या वापरण्याकरता अ‍ॅपसाठी, या स्थान सेवा सुरू करणे आणि त्या तुमच्या टॅबलेटवर उपलब्ध करणे आवश्यक आहे."</string>
-    <string name="permdesc_accessCoarseLocation" product="tv" msgid="8109788578615250690">"हे अॅप फक्त फोरग्राउंडमध्ये असतानाच, सेल टॉवर आणि वाय-फाय नेटवर्क सारख्या नेटवर्क स्रोतवर आधारित तुमचे स्थान मिळवू शकते. अॅपने वापरण्याकरिता, या स्थान सेवा सुरू करणे आणि त्या तुमच्या Android TV डिव्हाइसवर उपलब्ध करणे आवश्यक आहे."</string>
+    <string name="permdesc_accessCoarseLocation" product="tv" msgid="8109788578615250690">"हे ॲप फक्त फोरग्राउंडमध्ये असतानाच, सेल टॉवर आणि वाय-फाय नेटवर्क सारख्या नेटवर्क स्रोतवर आधारित तुमचे स्थान मिळवू शकते. ॲपने वापरण्याकरिता, या स्थान सेवा सुरू करणे आणि त्या तुमच्या Android TV डिव्हाइसवर उपलब्ध करणे आवश्यक आहे."</string>
     <string name="permdesc_accessCoarseLocation" product="default" msgid="854896049371048754">"हे अ‍ॅप फक्त फोरग्राउंडमध्ये असतानाच, सेल टॉवर आणि वाय-फाय नेटवर्क सारख्या नेटवर्क स्रोतवर आधारित तुमचे स्थान मिळवू शकते. ते वापरण्याकरता अ‍ॅपसाठी, या स्थान सेवा सुरू करणे आणि त्या तुमच्या फोनवर उपलब्ध करणे आवश्यक आहे."</string>
     <string name="permlab_accessBackgroundLocation" msgid="3965397804300661062">"बॅकग्राउंडमध्ये स्थान अ‍ॅक्सेस करू शकतो"</string>
     <string name="permdesc_accessBackgroundLocation" msgid="1096394429579210251">"याला अंदाजे किंवा अचूक स्थान अ‍ॅक्सेस करण्यास अतिरिक्त मंजूरी दिल्यास, बॅकग्राउंडमध्ये चालतांना अ‍ॅप स्थान अ‍ॅक्सेस करू शकतो."</string>
@@ -432,12 +432,12 @@
     <string name="permdesc_recordAudio" msgid="4245930455135321433">"हा अ‍ॅप कोणत्याही वेळी मायक्रोफोन वापरून ऑडिओ रेकॉर्ड करू शकता."</string>
     <string name="permlab_sim_communication" msgid="2935852302216852065">"सिम वर कमांड पाठवा"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"अ‍ॅप ला सिम वर कमांड पाठविण्‍याची अनुमती देते. हे खूप धोकादायक असते."</string>
-    <string name="permlab_activityRecognition" msgid="3634590230567608356">"शारीरिक अॅक्टिव्हिटी ओळखा"</string>
-    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"हे अ‍ॅप तुमच्या शारीरिक अॅक्टिव्हिटी ओळखू शकते."</string>
+    <string name="permlab_activityRecognition" msgid="3634590230567608356">"शारीरिक ॲक्टिव्हिटी ओळखा"</string>
+    <string name="permdesc_activityRecognition" msgid="3143453925156552894">"हे अ‍ॅप तुमच्या शारीरिक ॲक्टिव्हिटी ओळखू शकते."</string>
     <string name="permlab_camera" msgid="3616391919559751192">"चित्रे आणि व्हिडिओ घ्या"</string>
-    <string name="permdesc_camera" msgid="5392231870049240670">"हा अ‍ॅप कोणत्याही वेळी कॅमेरा वापरून चित्रेे घेऊ आणि व्ह‍िडिअो रेकॉर्ड करू शकतो."</string>
-    <string name="permlab_systemCamera" msgid="4074081285026193898">"फोटो आणि व्हिडिओ काढण्यासाठी अॅप्लिकेशन किंवा सेवेला सिस्टम कॅमेरे अॅक्सेस करण्याची अनुमती द्या"</string>
-    <string name="permdesc_systemCamera" msgid="6488131672529669229">"हे विशेषाधिकृत आहे | सिस्टम अॅप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. अॅपला android.permission.CAMERA परवानगी देण्याचीदेखील आवश्यकता आहे"</string>
+    <string name="permdesc_camera" msgid="5392231870049240670">"हा अ‍ॅप कोणत्याही वेळी कॅमेरा वापरून चित्रेे घेऊ आणि व्ह‍िडिओ रेकॉर्ड करू शकतो."</string>
+    <string name="permlab_systemCamera" msgid="4074081285026193898">"फोटो आणि व्हिडिओ काढण्यासाठी ॲप्लिकेशन किंवा सेवेला सिस्टम कॅमेरे ॲक्सेस करण्याची अनुमती द्या"</string>
+    <string name="permdesc_systemCamera" msgid="6488131672529669229">"हे विशेषाधिकृत आहे | सिस्टम ॲप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपला android.permission.CAMERA परवानगी देण्याचीदेखील आवश्यकता आहे"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"व्हायब्रेट नियंत्रित करा"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"अ‍ॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string>
@@ -445,24 +445,24 @@
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा अ‍ॅक्सेस करा"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"आपल्‍या हस्तक्षेपाशिवाय अ‍ॅपला कॉल करण्‍यासाठी IMS सेवा वापरण्याची अनुमती देते."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"फोन स्थिती आणि ओळख वाचा"</string>
-    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"डिव्हाइस च्या फोन वैशिष्ट्यांवर अ‍ॅक्सेस करण्यास अॅपला अनुमती देते. ही परवानगी कॉल अॅक्टिव्हेट असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस आयडी आणि कॉलद्वारे कनेक्ट केलेला रिमोट नंबर निर्धारित करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"डिव्हाइस च्या फोन वैशिष्ट्यांवर अ‍ॅक्सेस करण्यास ॲपला अनुमती देते. ही परवानगी कॉल ॲक्टिव्हेट असला किंवा नसला तरीही, फोन नंबर आणि डिव्हाइस आयडी आणि कॉलद्वारे कनेक्ट केलेला रिमोट नंबर निर्धारित करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_manageOwnCalls" msgid="1503034913274622244">"प्रणालीच्या माध्यमातून कॉल रूट करा"</string>
-    <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"कॉल करण्याचा अनुभव सुधारण्यासाठी अॅपला त्याचे कॉल प्रणालीच्या माध्यमातून रूट करू देते."</string>
+    <string name="permdesc_manageOwnCalls" msgid="6552974537554717418">"कॉल करण्याचा अनुभव सुधारण्यासाठी ॲपला त्याचे कॉल प्रणालीच्या माध्यमातून रूट करू देते."</string>
     <string name="permlab_callCompanionApp" msgid="3599252979411970473">"सिस्टम वापरून कॉल पाहा आणि नियंत्रण ठेवा."</string>
-    <string name="permdesc_callCompanionApp" msgid="4567344683275099090">"डिव्हाइसवर येणार कॉल पाहण्यासाठी आणि नियंत्रित करण्यासाठी अॅपला अनुमती देते. यामध्ये कॉल करण्यासाठी कॉलचा नंबर आणि कॉलची स्थिती यासारख्या माहितीचा समावेश असतो."</string>
-    <string name="permlab_acceptHandover" msgid="2661534649736022409">"दुसऱ्या अॅपवरून कॉल करणे सुरू ठेवा"</string>
-    <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"दुसऱ्या अॅपमध्ये सुरू झालेल्या कॉलला पुढे सुरू ठेवण्याची अॅपला अनुमती देते."</string>
+    <string name="permdesc_callCompanionApp" msgid="4567344683275099090">"डिव्हाइसवर येणार कॉल पाहण्यासाठी आणि नियंत्रित करण्यासाठी ॲपला अनुमती देते. यामध्ये कॉल करण्यासाठी कॉलचा नंबर आणि कॉलची स्थिती यासारख्या माहितीचा समावेश असतो."</string>
+    <string name="permlab_acceptHandover" msgid="2661534649736022409">"दुसऱ्या ॲपवरून कॉल करणे सुरू ठेवा"</string>
+    <string name="permdesc_acceptHandovers" msgid="4570660484220539698">"दुसऱ्या ॲपमध्ये सुरू झालेल्या कॉलला पुढे सुरू ठेवण्याची ॲपला अनुमती देते."</string>
     <string name="permlab_readPhoneNumbers" msgid="6108163940932852440">"फोन नंबर वाचा"</string>
-    <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"अॅपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते."</string>
+    <string name="permdesc_readPhoneNumbers" msgid="8559488833662272354">"ॲपला डिव्हाइसच्या फोन नंबरमध्ये प्रवेश करण्याची अनुमती देते."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"टॅबलेट निष्क्रिय होण्यापासून प्रतिबंधित करा"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2861011879203144533">"तुमच्या Android TV डिव्हाइसला स्लीप मोडमध्ये जाण्यापासून थांबवा"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"फोन निष्‍क्रिय होण्‍यापासून प्रतिबंधित करा"</string>
     <string name="permdesc_wakeLock" product="tablet" msgid="7311319824400447868">"टॅब्लेटला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_wakeLock" product="tv" msgid="7198875852034040387">"Android TV डिव्हाइसला स्लीप मोडमध्ये जाण्यापासून प्रतिबंधित करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_wakeLock" product="tv" msgid="7198875852034040387">"Android TV डिव्हाइसला स्लीप मोडमध्ये जाण्यापासून प्रतिबंधित करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permdesc_wakeLock" product="default" msgid="8559100677372928754">"फोनला निष्क्रिय होण्यापासून प्रतिबंधित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_transmitIr" msgid="7545858504238530105">"इन्फ्रारेड प्रक्षेपण करा"</string>
     <string name="permdesc_transmitIr" product="tablet" msgid="5358308854306529170">"अ‍ॅप ला टॅब्‍लेटच्‍या इन्‍फ्रारेड ट्रान्‍समीटरचा वापर करण्‍याची अनुमती देते."</string>
-    <string name="permdesc_transmitIr" product="tv" msgid="2752076865253892198">"अॅपला Android TV डिव्हाइसचा इन्‍फ्रारेड ट्रान्‍समीटर वापरण्‍याची अनुमती देते."</string>
+    <string name="permdesc_transmitIr" product="tv" msgid="2752076865253892198">"ॲपला Android TV डिव्हाइसचा इन्‍फ्रारेड ट्रान्‍समीटर वापरण्‍याची अनुमती देते."</string>
     <string name="permdesc_transmitIr" product="default" msgid="7957763745020300725">"अ‍ॅप ला फोनच्‍या इन्‍फ्रारेड ट्रान्‍समीटरचा वापर करण्‍याची अनुमती देते."</string>
     <string name="permlab_setWallpaper" msgid="6627192333373465143">"वॉलपेपर सेट करा"</string>
     <string name="permdesc_setWallpaper" msgid="7373447920977624745">"सिस्टम वॉलपेपर सेट करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
@@ -470,11 +470,11 @@
     <string name="permdesc_setWallpaperHints" msgid="8235784384223730091">"सिस्टम वॉलपेपर आकार सूचना सेट करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_setTimeZone" msgid="2945079801013077340">"टाइम झोन सेट करा"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="1676983712315827645">"टॅब्लेटचा टाइम झोन बदलण्यासाठी अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_setTimeZone" product="tv" msgid="8957160816851601080">"तुमच्या Android TV डिव्हाइसचा टाइम झोन बदलण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_setTimeZone" product="tv" msgid="8957160816851601080">"तुमच्या Android TV डिव्हाइसचा टाइम झोन बदलण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"फोनचा टाइम झोन बदलण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"डिव्हाइसवरील खाती शोधा"</string>
     <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"टॅब्लेटद्वारे ज्ञात खात्यांची सूची मिळवण्यासाठी अ‍ॅप ला अनुमती देते. यात तुम्ही इंस्टॉल केलेल्या अनुप्रयोगांद्वारे तयार केलेली कोणतीही खाती समाविष्ट होऊ शकतात."</string>
-    <string name="permdesc_getAccounts" product="tv" msgid="1394648459318596337">"Android TV डिव्हाइसला माहीत असलेल्या अॅपला खात्यांची सूची मिळवण्यासाठी अनुमती देते. यामध्ये तुम्ही इंस्टॉल केलेल्या अॅप्लिकेशननी तयार केलेल्या खात्यांचाही समावेश असू शकतो."</string>
+    <string name="permdesc_getAccounts" product="tv" msgid="1394648459318596337">"Android TV डिव्हाइसला माहीत असलेल्या ॲपला खात्यांची सूची मिळवण्यासाठी अनुमती देते. यामध्ये तुम्ही इंस्टॉल केलेल्या ॲप्लिकेशननी तयार केलेल्या खात्यांचाही समावेश असू शकतो."</string>
     <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"फोनद्वारे ज्ञात खात्यांची सूची मिळवण्यासाठी अ‍ॅप ला अनुमती देते. यात तुम्ही इंस्टॉल केलेल्या अनुप्रयोगांद्वारे तयार केलेली कोणतीही खाती समाविष्ट करू शकतात."</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"नेटवर्क कनेक्शन पहा"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"कोणती नेटवर्क अस्तित्वात आहेत आणि कनेक्ट केलेली आहेत यासारख्या नेटवर्क कनेक्शनविषयीची माहिती पाहण्यासाठी अ‍ॅप ला अनुमती देते."</string>
@@ -487,45 +487,45 @@
     <string name="permlab_accessWifiState" msgid="5202012949247040011">"वाय-फाय कनेक्शन पहा"</string>
     <string name="permdesc_accessWifiState" msgid="5002798077387803726">"वाय-फाय सक्षम केले आहे किंवा नाही आणि कनेक्ट केलेल्या वाय-फाय डीव्हाइसचे नाव यासारख्या, वाय-फाय नेटवर्किंग विषयीची माहिती पाहण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_changeWifiState" msgid="6550641188749128035">"वाय-फाय वरून कनेक्ट करा आणि डिस्कनेक्ट करा"</string>
-    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"वाय-फाय अ‍ॅक्सेस बिंदूंवर कनेक्ट करण्यासाठी आणि त्यावरून डिस्कनेक्ट करण्यासाठी आणि वाय-फाय नेटवर्कसाठी डिव्हाइस कॉंफिगरेशनमध्ये बदल करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_changeWifiState" msgid="7137950297386127533">"वाय-फाय अ‍ॅक्सेस बिंदूंवर कनेक्ट करण्यासाठी आणि त्यावरून डिस्कनेक्ट करण्यासाठी आणि वाय-फाय नेटवर्कसाठी डिव्हाइस कॉंफिगरेशनमध्ये बदल करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"वाय-फाय मल्‍टिकास्‍ट रिसेप्‍शनला अनुमती द्या"</string>
     <string name="permdesc_changeWifiMulticastState" product="tablet" msgid="7969774021256336548">"मल्टिकास्ट पत्ते वापरून फक्त तुमच्या टॅब्लेटवर नाही, तर वाय-फाय नेटवर्कवरील सर्व डीव्हाइसवर पाठविलेले पॅकेट प्राप्त करण्यासाठी अ‍ॅप ला अनुमती देते. हे मल्टिकास्टखेरिज इतर मोडसाठी अधिक पॉवर वापरते."</string>
-    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9115646511110555589">"फक्त तुमच्या Android TV डिव्हाइसलाच नाही, तर मल्टिकास्ट पत्ते वापरून एका वाय-फाय नेटवर्कवरील सर्व डिव्हाइसवर पाठविलेली पॅकेट प्राप्त करण्यासाठी अॅपला अनुमती देते. हे मल्टिकास्ट मोड नसताना वापरल्या जाणाऱ्या ऊर्जेपेक्षा अधिक उर्जा वापरते."</string>
+    <string name="permdesc_changeWifiMulticastState" product="tv" msgid="9115646511110555589">"फक्त तुमच्या Android TV डिव्हाइसलाच नाही, तर मल्टिकास्ट पत्ते वापरून एका वाय-फाय नेटवर्कवरील सर्व डिव्हाइसवर पाठविलेली पॅकेट प्राप्त करण्यासाठी ॲपला अनुमती देते. हे मल्टिकास्ट मोड नसताना वापरल्या जाणाऱ्या ऊर्जेपेक्षा अधिक उर्जा वापरते."</string>
     <string name="permdesc_changeWifiMulticastState" product="default" msgid="6851949706025349926">"मल्टिकास्ट पत्ते वापरून फक्त तुमच्या फोनवर नाही, तर वाय-फाय नेटवर्कवरील सर्व डीव्हाइसवर पाठविलेले पॅकेट प्राप्त करण्यासाठी अ‍ॅप ला अनुमती देते. हे मल्टिकास्टखेरिज इतर मोडसाठी अधिक पॉवर वापरते."</string>
     <string name="permlab_bluetoothAdmin" msgid="6006967373935926659">"ब्लूटूथ सेटिंग्ज अ‍ॅक्सेस करा"</string>
     <string name="permdesc_bluetoothAdmin" product="tablet" msgid="6921177471748882137">"स्थानिक ब्लूटूथ टॅबलेट कॉंफिगर करण्याकरिता आणि दूरस्थ डिव्हाइस शोधण्यासाठी आणि त्यासह जोडण्यासाठी अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3174333400857321862">"तुमच्या Android TV डिव्हाइसवर ब्लूटूथ कॉंफिगर करण्याकरिता आणि पेअर केलेली आणि रीमोट डिव्हाइस शोधण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_bluetoothAdmin" product="tv" msgid="3174333400857321862">"तुमच्या Android TV डिव्हाइसवर ब्लूटूथ कॉंफिगर करण्याकरिता आणि पेअर केलेली आणि रीमोट डिव्हाइस शोधण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permdesc_bluetoothAdmin" product="default" msgid="8931682159331542137">"स्थानिक ब्लूटूथ फोन कॉंफिगर करण्याकरिता आणि दूरस्थ डिव्हाइस शोधण्यासाठी आणि त्यासह जोडण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_accessWimaxState" msgid="4195907010610205703">"WiMAX कनेक्ट करा आणि त्यावरून डिस्कनेक्ट करा"</string>
     <string name="permdesc_accessWimaxState" msgid="6360102877261978887">"WiMAX सक्षम केले आहे किंवा नाही आणि कनेक्ट केलेल्या कोणत्याही WiMAX नेटवर्क विषयीची माहिती निर्धारित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX स्थिती बदला"</string>
     <string name="permdesc_changeWimaxState" product="tablet" msgid="3156456504084201805">"WiMAX नेटवर्कवर टॅबलेट कनेक्ट करण्यास आणि त्यावरून टॅबलेट डिस्कनेक्ट करण्यास अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_changeWimaxState" product="tv" msgid="4518633298024146973">"अॅपला तुमच्या Android TV डिव्हाइसशी कनेक्ट करण्याची आणि तुमचे Android TV डिव्हाइस WiMAX नेटवर्कवरून डिस्कनेक्ट करण्याची परवानगी देते."</string>
+    <string name="permdesc_changeWimaxState" product="tv" msgid="4518633298024146973">"ॲपला तुमच्या Android TV डिव्हाइसशी कनेक्ट करण्याची आणि तुमचे Android TV डिव्हाइस WiMAX नेटवर्कवरून डिस्कनेक्ट करण्याची परवानगी देते."</string>
     <string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"WiMAX नेटवर्कवर फोन कनेक्ट करण्यास आणि त्यावरून फोन डिस्कनेक्ट करण्यास अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_bluetooth" msgid="6127769336339276828">"ब्लूटूथ डीव्हाइससह जोडा"</string>
     <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"टॅबलेटवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_bluetooth" product="tv" msgid="55662070067295183">"Android TV डिव्हाइसवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन तयार करण्यासाठी आणि स्वीकारण्यासाठी, अॅपला अनुमती देते."</string>
+    <string name="permdesc_bluetooth" product="tv" msgid="55662070067295183">"Android TV डिव्हाइसवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन तयार करण्यासाठी आणि स्वीकारण्यासाठी, ॲपला अनुमती देते."</string>
     <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"फोनवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_nfc" msgid="4423351274757876953">"फील्ड जवळील कम्युनिकेशन नियंत्रित करा"</string>
-    <string name="permdesc_nfc" msgid="7120611819401789907">"फील्ड जवळील कम्युनिकेशन (NFC) टॅग, कार्डे आणि वाचक यांच्यासह संवाद करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_nfc" msgid="7120611819401789907">"फील्ड जवळील कम्युनिकेशन (NFC) टॅग, कार्डे आणि वाचक यांच्यासह संवाद करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"तुमचे स्क्रीन लॉक अक्षम करा"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कीलॉक आणि कोणतीही संबद्ध पासवर्ड सुरक्षितता अक्षम करण्यासाठी अ‍ॅप ला अनुमती देते. उदाहरणार्थ, येणारा फोन कॉल प्राप्त करताना फोन कीलॉक अक्षम करतो, नंतर जेव्हा कॉल समाप्त होतो तेव्हा तो कीलॉक पुन्हा-सक्षम करतो."</string>
     <string name="permlab_requestPasswordComplexity" msgid="202650535669249674">"स्क्रीन लॉक क्लिष्टतेची विनंती करा"</string>
     <string name="permdesc_requestPasswordComplexity" msgid="4730994229754212347">"अ‍ॅपला स्क्रीन लॉक क्लिष्टता पातळी (उच्च, मध्यम, खालची किंवा काहीही नाही) जाणून घेऊ देते, जी लांबीची संभाव्य रेंज आणि स्क्रीन लॉकचा प्रकार सूचित करते. अ‍ॅप वापरकर्त्यांना असेदेखील सुचवू शकते की त्यांनी स्क्रीन लॉक ठराविक पातळीपर्यंत अपडेट करावे, परंतु वापरकर्ते त्याकडे मोकळेपणाने दुर्लक्ष करू शकतात आणि तेथून नेव्हिगेट करू शकतात. स्क्रीन लॉक प्लेनटेक्स्टमध्ये स्टोअर केले जात नसल्यामुळे अ‍ॅपला नेमका पासवर्ड माहीत नसतो याची नोंद घ्या."</string>
     <string name="permlab_useBiometric" msgid="8837753668509919318">"बायोमेट्रिक हार्डवेअर वापरा"</string>
-    <string name="permdesc_useBiometric" msgid="8389855232721612926">"ऑथेंटिकेशनसाठी बायोमेट्रिक हार्डवेअरचा वापर करण्याची अॅपला अनुमती देते"</string>
+    <string name="permdesc_useBiometric" msgid="8389855232721612926">"ऑथेंटिकेशनसाठी बायोमेट्रिक हार्डवेअरचा वापर करण्याची ॲपला अनुमती देते"</string>
     <string name="permlab_manageFingerprint" msgid="5640858826254575638">"फिंगरप्रिंट हार्डवेअर व्यवस्थापित करा"</string>
-    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"वापर करण्याकरिता फिंगरप्रिंट टेम्पलेट जोडण्यासाठी आणि हटविण्यासाठी पद्धती रद्द करण्यास अॅपला अनुमती देते."</string>
+    <string name="permdesc_manageFingerprint" msgid="178208705828055464">"वापर करण्याकरिता फिंगरप्रिंट टेम्पलेट जोडण्यासाठी आणि हटविण्यासाठी पद्धती रद्द करण्यास ॲपला अनुमती देते."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"फिंगरप्रिंट हार्डवेअर वापरा"</string>
-    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"प्रमाणीकरणाकरिता फिंगरप्रिंट हार्डवेअरचा वापर करण्यासाठी अॅपला अनुमती देते"</string>
+    <string name="permdesc_useFingerprint" msgid="9165097460730684114">"प्रमाणीकरणाकरिता फिंगरप्रिंट हार्डवेअरचा वापर करण्यासाठी ॲपला अनुमती देते"</string>
     <string name="permlab_audioWrite" msgid="2661772059799779292">"तुमच्या संगीत संग्रहामध्ये सुधारणा करा"</string>
-    <string name="permdesc_audioWrite" msgid="8888544708166230494">"अॅपला तुमच्या संगीत संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
+    <string name="permdesc_audioWrite" msgid="8888544708166230494">"ॲपला तुमच्या संगीत संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
     <string name="permlab_videoWrite" msgid="128769316366746446">"तुमच्या व्हिडिओ संग्रहामध्ये सुधारणा करा"</string>
-    <string name="permdesc_videoWrite" msgid="5448565757490640841">"अॅपला तुमच्या व्हिडिओ संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
+    <string name="permdesc_videoWrite" msgid="5448565757490640841">"ॲपला तुमच्या व्हिडिओ संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
     <string name="permlab_imagesWrite" msgid="3391306186247235510">"तुमच्या फोटो संग्रहामध्ये सुधारणा करा"</string>
-    <string name="permdesc_imagesWrite" msgid="7073662756617474375">"अॅपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
+    <string name="permdesc_imagesWrite" msgid="7073662756617474375">"ॲपला तुमच्या फोटो संग्रहामध्ये सुधारणा करण्याची अनुमती देते."</string>
     <string name="permlab_mediaLocation" msgid="8675148183726247864">"तुमच्या मीडिया संग्रहातून स्थाने वाचा"</string>
-    <string name="permdesc_mediaLocation" msgid="2237023389178865130">"अॅपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
+    <string name="permdesc_mediaLocation" msgid="2237023389178865130">"ॲपला तुमच्या मीडिया संग्रहामध्येील स्थाने वाचण्यासाठी अनुमती देते."</string>
     <string name="biometric_dialog_default_title" msgid="881952973720613213">"हे तुम्हीच आहात याची पडताळणी करा"</string>
     <string name="biometric_error_hw_unavailable" msgid="645781226537551036">"बायोमेट्रिक हार्डवेअर उपलब्ध नाही"</string>
     <string name="biometric_error_user_canceled" msgid="2260175018114348727">"ऑथेंटिकेशन रद्द केले"</string>
@@ -557,7 +557,7 @@
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"फिंगरप्रिंट आयकन"</string>
     <string name="permlab_manageFace" msgid="7262837876352591553">"फेस अनलॉक हार्डवेअर व्यवस्थापित करा"</string>
-    <string name="permdesc_manageFace" msgid="8919637120670185330">"अॅपला वापरासाठी चेहरा टेम्पलेट जोडण्याच्या आणि हटवण्याच्या पद्धती जारी करू देते."</string>
+    <string name="permdesc_manageFace" msgid="8919637120670185330">"ॲपला वापरासाठी चेहरा टेम्पलेट जोडण्याच्या आणि हटवण्याच्या पद्धती जारी करू देते."</string>
     <string name="permlab_useFaceAuthentication" msgid="2565716575739037572">"फेस अनलॉक हार्डवेअर वापरा"</string>
     <string name="permdesc_useFaceAuthentication" msgid="4712947955047607722">"अ‍ॅपला ऑथेंटिकेशनसाठी फेस अनलॉक हार्डवेअर वापरण्याची अनुमती देते"</string>
     <string name="face_recalibrate_notification_name" msgid="1913676850645544352">"फेस अनलॉक"</string>
@@ -606,15 +606,15 @@
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"सिंक आकडेवारी वाचा"</string>
     <string name="permdesc_readSyncStats" msgid="1510143761757606156">"सिंक इव्हेंटचा इतिहास आणि किती डेटाचे सिंक केले आहे यासह, खात्याची सिंक स्थिती वाचण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_sdcardRead" msgid="1438933556581438863">"तुमच्या शेअर केलेल्या स्टोरेजचे आशय वाचते"</string>
-    <string name="permdesc_sdcardRead" msgid="1804941689051236391">"अॅपला तुमच्या शेअर केलेल्या स्टोरेजचे आशय वाचण्याची अनुमती देते."</string>
+    <string name="permdesc_sdcardRead" msgid="1804941689051236391">"ॲपला तुमच्या शेअर केलेल्या स्टोरेजचे आशय वाचण्याची अनुमती देते."</string>
     <string name="permlab_sdcardWrite" msgid="9220937740184960897">"तुमच्या शेअर केलेल्या स्टोरेजच्या आशयांमध्ये सुधारणा करा किंवा हटवा"</string>
-    <string name="permdesc_sdcardWrite" msgid="2834431057338203959">"अॅपला तुमच्या शेअर केलेल्या स्टोरेजचे आशय लिहिण्याची अनमती देते."</string>
+    <string name="permdesc_sdcardWrite" msgid="2834431057338203959">"ॲपला तुमच्या शेअर केलेल्या स्टोरेजचे आशय लिहिण्याची अनमती देते."</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"SIP कॉल करा/प्राप्त करा"</string>
-    <string name="permdesc_use_sip" msgid="2297804849860225257">"अॅपला SIP कॉल करण्‍याची आणि प्राप्त करण्‍याची अनुमती देते."</string>
+    <string name="permdesc_use_sip" msgid="2297804849860225257">"ॲपला SIP कॉल करण्‍याची आणि प्राप्त करण्‍याची अनुमती देते."</string>
     <string name="permlab_register_sim_subscription" msgid="3166535485877549177">"नवीन टेलिकॉम सिम कनेक्शनची नोंदणी करा"</string>
-    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"नवीन टेलिकॉम सिम कनेक्शनची नोंदणी करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_register_sim_subscription" msgid="2138909035926222911">"नवीन टेलिकॉम सिम कनेक्शनची नोंदणी करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_register_call_provider" msgid="108102120289029841">"नवीन टेलिकॉम कनेक्शनची नोंदणी करा"</string>
-    <string name="permdesc_register_call_provider" msgid="7034310263521081388">"नवीन टेलिकॉम कनेक्शनची नोंदणी करण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_register_call_provider" msgid="7034310263521081388">"नवीन टेलिकॉम कनेक्शनची नोंदणी करण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_connection_manager" msgid="1116193254522105375">"टेलिकॉम कनेक्शन व्यवस्थापित करा"</string>
     <string name="permdesc_connection_manager" msgid="5925480810356483565">"टेलिकॉम कनेक्शन व्यवस्थापित करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_bind_incall_service" msgid="6773648341975287125">"कॉल-मधील स्‍क्रीनशी परस्‍परसंवाद करा"</string>
@@ -634,7 +634,7 @@
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"सूचना ऐकणार्‍या सेवेशी प्रतिबद्ध"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"होल्‍डरला सूचना ऐकणार्‍या सेवेच्‍या शीर्ष-दर्जाच्या इंटरफेसशी प्रतिबद्ध करण्‍याची अनुमती देते. सामान्‍य अ‍ॅप्‍ससाठी कधीही आवश्‍यक नसावे."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"एका अट प्रदाता सेवेवर प्रतिबद्ध करा"</string>
-    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"स्थिती प्रदाता सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यक नसते."</string>
+    <string name="permdesc_bindConditionProviderService" msgid="1680513931165058425">"स्थिती प्रदाता सेवेचा शीर्ष-स्तर इंटरफेस प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य ॲप्सकरिता कधीही आवश्यक नसते."</string>
     <string name="permlab_bindDreamService" msgid="4153646965978563462">"स्‍वप्न सेवेवर प्रतिबद्ध करा"</string>
     <string name="permdesc_bindDreamService" msgid="7325825272223347863">"होल्‍डरला स्‍वप्नसेवेच्या शीर्ष-स्‍तराच्या इंटरफेसशी प्रतिबद्ध करण्‍यास अनुमती देते. सामान्‍य अ‍ॅप्‍सकरिता कधीही आवश्‍यक नसते."</string>
     <string name="permlab_invokeCarrierSetup" msgid="3699600833975117478">"वाहकाद्वारे-प्रदान केलेल्‍या कॉन्‍फिगरेशन अ‍ॅपची विनंती करा"</string>
@@ -644,7 +644,7 @@
     <string name="permlab_setInputCalibration" msgid="4902620118878467615">"इनपुट डिव्हाइस कॅलिब्रेशन बदला"</string>
     <string name="permdesc_setInputCalibration" msgid="4527511047549456929">"स्पर्श स्क्रीनची कॅलिब्रेशन प्राचले सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. सामान्य अ‍ॅप्स साठी कधीही आवश्यक नसते."</string>
     <string name="permlab_accessDrmCertificates" msgid="7436886640723203615">"DRM प्रमाणपत्रे अ‍ॅक्सेस करा"</string>
-    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM प्रमाणपत्रांची तरतूद करण्यासाठी आणि वापरण्यासाठी अनुप्रयोगास अनुमती देते. सामान्य अॅप्सकरिता कधीही आवश्यकता नसते."</string>
+    <string name="permdesc_accessDrmCertificates" msgid="8073288354426159089">"DRM प्रमाणपत्रांची तरतूद करण्यासाठी आणि वापरण्यासाठी अनुप्रयोगास अनुमती देते. सामान्य ॲप्सकरिता कधीही आवश्यकता नसते."</string>
     <string name="permlab_handoverStatus" msgid="7820353257219300883">"Android बीम स्थानांतरण स्थिती प्राप्त करा"</string>
     <string name="permdesc_handoverStatus" msgid="4788144087245714948">"वर्तमान Android बीम स्थानांतरणांविषयी माहिती प्राप्त करण्यासाठी या अनुप्रयोगास अनुमती देते"</string>
     <string name="permlab_removeDrmCertificates" msgid="7044888287209892751">"DRM प्रमाणपत्रे काढा"</string>
@@ -652,9 +652,9 @@
     <string name="permlab_bindCarrierMessagingService" msgid="1490229371796969158">"एका वाहक मेसेजिंग सेवेसाठी प्रतिबद्ध"</string>
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"वाहक मेसेजिंग सेवेचा शीर्ष-स्तर इंटरफेस बाइंड करण्यासाठी होल्डरला अनुमती देतो. सामान्‍य अ‍ॅप्‍सकरिता हे कधीही आवश्‍यक नसते."</string>
     <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"वाहक सेवांवर प्रतिबद्ध करा"</string>
-    <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"वाहक सेवांवर प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यकता नसावी."</string>
+    <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"वाहक सेवांवर प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य ॲप्ससाठी कधीही आवश्यकता नसावी."</string>
     <string name="permlab_access_notification_policy" msgid="4247510821662059671">"व्यत्यय आणू नका अ‍ॅक्सेस करा"</string>
-    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी अॅपला अनुमती देते."</string>
+    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी ॲपला अनुमती देते."</string>
     <string name="permlab_startViewPermissionUsage" msgid="5484728591597709944">"व्ह्यू परवानगी वापर सुरू करा"</string>
     <string name="permdesc_startViewPermissionUsage" msgid="4808345878203594428">"धारकास अ‍ॅपसाठी परवानगी वापरणे सुरू करण्याची अनुमती देते. सामान्य अ‍ॅप्ससाठी कधीही आवश्यकता नसते."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करा"</string>
@@ -801,7 +801,7 @@
     <string name="sipAddressTypeHome" msgid="6093598181069359295">"घर"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"कार्य"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"अन्य"</string>
-    <string name="quick_contacts_not_available" msgid="746098007828579688">"हा संपर्क पाहण्‍यासाठी कोणतीही अॅक्टिव्हिटी आढळली नाही."</string>
+    <string name="quick_contacts_not_available" msgid="746098007828579688">"हा संपर्क पाहण्‍यासाठी कोणतीही ॲक्टिव्हिटी आढळली नाही."</string>
     <string name="keyguard_password_enter_pin_code" msgid="3037685796058495017">"पिन कोड टाइप करा"</string>
     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK आणि नवीन पिन कोड टाइप करा"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK कोड"</string>
@@ -942,10 +942,10 @@
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"ब्राउझरने भेट दिलेल्या सर्व URL चा इतिहास आणि ब्राउझरचे सर्व बुकमार्क वाचण्यास अ‍ॅप ला अनुमती देते. टीप: या परवानगीची तृतीय-पक्ष ब्राउझरद्वारे किंवा वेब ब्राउझिंग क्षमता असलेल्या अन्य अनुप्रयोगांद्वारे अंमलबजावणी करू शकत नाही."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"वेब बुकमार्क आणि इतिहास लिहा"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"तुमच्या टॅब्लेटवर स्टोअर केलेला ब्राउझरचा इतिहास किंवा बुकमार्क सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. हे ब्राउझर डेटा मिटविण्यासाठी किंवा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. टीप: ही परवानगी तृतीय पक्ष ब्राउझरद्वारे किंवा वेब ब्राउझिंग क्षमतांसह अन्य अ‍ॅप्लिकेशनद्वारे अंमलबजावणी करण्याची टीप देऊ शकते."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="6340829212433680418">"तुमच्या Android TV डिव्हाइसवर साठवलेला ब्राउझरचा इतिहास किंवा बुकमार्क सुधारित करण्यासाठी अॅप ला अनुमती देते. हे अॅपला ब्राउझर डेटा मिटवण्याची किंवा सुधारित करण्याची परवानगी देते. टीप: ही परवानगी तृतीय पक्ष ब्राउझरद्वारे किंवा वेब ब्राउझिंग क्षमतांसह अन्य अ‍ॅप्लिकेशनद्वारे अंमलबजावणी करण्याची टीप देऊ शकते."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="6340829212433680418">"तुमच्या Android TV डिव्हाइसवर साठवलेला ब्राउझरचा इतिहास किंवा बुकमार्क सुधारित करण्यासाठी ॲप ला अनुमती देते. हे ॲपला ब्राउझर डेटा मिटवण्याची किंवा सुधारित करण्याची परवानगी देते. टीप: ही परवानगी तृतीय पक्ष ब्राउझरद्वारे किंवा वेब ब्राउझिंग क्षमतांसह अन्य अ‍ॅप्लिकेशनद्वारे अंमलबजावणी करण्याची टीप देऊ शकते."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"तुमच्या फोनवर स्टोअर केलेला ब्राउझरचा इतिहास किंवा बुकमार्क सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. हे ब्राउझर डेटा मिटविण्यासाठी किंवा सुधारित करण्यासाठी अ‍ॅप ला अनुमती देते. टीप: ही परवानगी तृतीय पक्ष ब्राउझरद्वारे किंवा वेब ब्राउझिंग क्षमतांसह अन्य अ‍ॅप्लिकेशनद्वारे अंमलबजावणी करण्याची टीप देऊ शकते."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"अलार्म सेट करा"</string>
-    <string name="permdesc_setAlarm" msgid="316392039157473848">"इंस्टॉल केलेल्या अलार्म घड्याळ अॅपमध्ये अलार्म सेट करण्यासाठी अॅपला अनुमती देते. काही अलार्म घड्याळ अॅप्समध्ये हे वैशिष्ट्य नसू शकते."</string>
+    <string name="permdesc_setAlarm" msgid="316392039157473848">"इंस्टॉल केलेल्या अलार्म घड्याळ ॲपमध्ये अलार्म सेट करण्यासाठी ॲपला अनुमती देते. काही अलार्म घड्याळ ॲप्समध्ये हे वैशिष्ट्य नसू शकते."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"व्हॉइसमेल जोडा"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"आपल्या व्हॉइसमेल इनबॉक्समध्ये मेसेज जोडण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ब्राउझर भौगोलिक स्थान परवानग्या सुधारित करा"</string>
@@ -1096,7 +1096,7 @@
     <string name="inputMethod" msgid="1653630062304567879">"इनपुट पद्धत"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"मजकूर क्रिया"</string>
     <string name="email" msgid="4560673117055050403">"ईमेल करा"</string>
-    <string name="email_desc" msgid="3638665569546416795">"निवडलेल्या अॅड्रेसवर ईमेल करा"</string>
+    <string name="email_desc" msgid="3638665569546416795">"निवडलेल्या ॲड्रेसवर ईमेल करा"</string>
     <string name="dial" msgid="1253998302767701559">"कॉल करा"</string>
     <string name="dial_desc" msgid="6573723404985517250">"निवडलेल्या फोन नंबरवर कॉल करा"</string>
     <string name="map" msgid="5441053548030107189">"नकाशा उघडा"</string>
@@ -1189,7 +1189,7 @@
     <string name="screen_compat_mode_hint" msgid="1064524084543304459">"सिस्टम सेटिंग्ज &gt; Apps &gt; डाउनलोड केलेले मध्ये हे पुन्हा-सुरू करा."</string>
     <string name="unsupported_display_size_message" msgid="6545327290756295232">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
     <string name="unsupported_display_size_show" msgid="7969129195360353041">"नेहमी दर्शवा"</string>
-    <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे Android OS च्या विसंगत आवृत्तीसाठी तयार केले होते आणि ते अनपेक्षित पद्धतीने काम करू शकते. अॅपची अपडेट केलेली आवृत्ती उपलब्ध असू शकते."</string>
+    <string name="unsupported_compile_sdk_message" msgid="4253168368781441759">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे Android OS च्या विसंगत आवृत्तीसाठी तयार केले होते आणि ते अनपेक्षित पद्धतीने काम करू शकते. ॲपची अपडेट केलेली आवृत्ती उपलब्ध असू शकते."</string>
     <string name="unsupported_compile_sdk_show" msgid="2681877855260970231">"नेहमी दर्शवा"</string>
     <string name="unsupported_compile_sdk_check_update" msgid="3312723623323216101">"अपडेट आहे का ते तपासा"</string>
     <string name="smv_application" msgid="3307209192155442829">"अ‍ॅप <xliff:g id="APPLICATION">%1$s</xliff:g> (प्रक्रिया <xliff:g id="PROCESS">%2$s</xliff:g>) ने तिच्या स्वयं-लागू केलेल्या StrictMode धोरणाचे उल्लंघन केले आहे."</string>
@@ -1219,7 +1219,7 @@
     <string name="dump_heap_ready_notification" msgid="1162196579925048701">"<xliff:g id="PROC">%1$s</xliff:g> हीप डंप तयार आहे"</string>
     <string name="dump_heap_notification_detail" msgid="3993078784053054141">"हीप डंप गोळा केले. शेअर करण्यासाठी टॅप करा."</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप शेअर करायचे?"</string>
-    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने तिची <xliff:g id="SIZE">%2$s</xliff:g> ची मेमरी मर्यादा ओलांडली आहे. तिच्या डेव्हलपरसोबत शेअर करण्यासाठी तुमच्याकरिता हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये अॅप्लिकेशनला अ‍ॅक्सेस असलेली तुमची कोणतीही वैयक्तिक माहिती असू शकते."</string>
+    <string name="dump_heap_text" msgid="8546022920319781701">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने तिची <xliff:g id="SIZE">%2$s</xliff:g> ची मेमरी मर्यादा ओलांडली आहे. तिच्या डेव्हलपरसोबत शेअर करण्यासाठी तुमच्याकरिता हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये ॲप्लिकेशनला अ‍ॅक्सेस असलेली तुमची कोणतीही वैयक्तिक माहिती असू शकते."</string>
     <string name="dump_heap_system_text" msgid="3236094872980706024">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने तिची <xliff:g id="SIZE">%2$s</xliff:g> ची मेमरी मर्यादा ओलांडली आहे. तुमच्यासाठी शेअर करण्याकरिता हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये प्रक्रियेला अ‍ॅक्सेस असलेली कोणतीही संवेदनशील वैयक्तिक माहिती असू शकते, ज्यामध्ये तुम्ही टाइप केलेल्या गोष्टींचा समावेश असू शकतो."</string>
     <string name="dump_heap_ready_text" msgid="1778041771455343067">"तुमच्यासाठी शेअर करण्याकरिता <xliff:g id="PROC">%1$s</xliff:g> च्या प्रक्रियेचे हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये प्रक्रियेला अ‍ॅक्सेस असलेली कोणतीही संवेदनशील वैयक्तिक माहिती असू शकते, ज्यामध्ये तुम्ही टाइप केलेल्या गोष्टींचा समावेश असू शकतो."</string>
     <string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string>
@@ -1244,45 +1244,18 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्म ध्वनी"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना ध्वनी"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">वाय-फाय नेटवर्क उपलब्ध</item>
-      <item quantity="one">वाय-फाय नेटवर्क उपलब्‍ध</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">खुले वाय-फाय नेटवर्क उपलब्ध</item>
-      <item quantity="one">खुले वाय-फाय नेटवर्क उपलब्‍ध</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"खुल्या वाय-फाय नेटवर्कशी कनेक्ट करा"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"वाय-फाय नेटवर्कशी कनेक्ट करत आहे"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"वाय-फाय नेटवर्कशी कनेक्ट केले"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"वाय-फाय नेटवर्कशी कनेक्ट करू शकत नाही"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"सर्व नेटवर्क पाहण्यासाठी टॅप करा"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"कनेक्ट करा"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"सर्व नेटवर्क"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"सुचवलेल्या वाय-फाय नेटवर्कना अनुमती द्यायची का?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> सुचवलेली नेटवर्क. डिव्हाइस आपोआप कनेक्ट होऊ शकते."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"अनुमती द्या"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"नाही, नको"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"वाय-फाय आपोआप चालू होईल"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"तुम्ही जेव्हा सेव्ह केलेल्या उच्च दर्जाच्या नेटवर्कजवळ असाल तेव्हा"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"पुन्हा चालू करू नका"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"वाय-फाय आपोआप चालू झाले"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"तुम्ही या सेव्ह केलेल्या नेटवर्कजवळ आहात: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"वाय-फाय नेटवर्कमध्‍ये साइन इन करा"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"नेटवर्कवर साइन इन करा"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_no_internet" msgid="5198100389964214865">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला इंटरनेट अ‍ॅक्सेस नाही"</string>
     <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"पर्यायांसाठी टॅप करा"</string>
-    <string name="mobile_no_internet" msgid="1445208572588803493">"मोबाइल नेटवर्कला इंटरनेट अॅक्सेस नाही"</string>
-    <string name="other_networks_no_internet" msgid="1553338015597653827">"नेटवर्कला इंटरनेट अॅक्सेस नाही"</string>
-    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"खाजगी DNS सर्व्हर अॅक्सेस करू शकत नाही"</string>
+    <string name="mobile_no_internet" msgid="1445208572588803493">"मोबाइल नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+    <string name="other_networks_no_internet" msgid="1553338015597653827">"नेटवर्कला इंटरनेट ॲक्सेस नाही"</string>
+    <string name="private_dns_broken_detailed" msgid="4293356177543535578">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"कनेक्ट केले"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ला मर्यादित कनेक्टिव्हिटी आहे"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"तरीही कनेक्ट करण्यासाठी टॅप करा"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"तुमच्या हॉटस्पॉट सेटिंग्जमधील बदल"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"तुमचा हॉटस्पॉट बँड बदलला आहे."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"हे डिव्हाइस तुमच्या फक्त ५GHz साठी प्राधान्याला सपोर्ट करत नाही. त्याऐवजी, हे डिव्हाइस ५GHz बँड उपलब्ध असताना वापरेल."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> वर स्विच केले"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> कडे इंटरनेटचा अ‍ॅक्सेस नसताना डिव्हाइस <xliff:g id="NEW_NETWORK">%1$s</xliff:g> वापरते. शुल्क लागू शकते."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> वरून <xliff:g id="NEW_NETWORK">%2$s</xliff:g> वर स्विच केले"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"अज्ञात नेटवर्क प्रकार"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाय-फाय ला कनेक्ट करू शकलो नाही"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"कनेक्शनला अनुमती द्यायची?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s अॅप्लिकेशन %2$s वायफाय नेटवर्कशी कनेक्ट करू इच्छित आहे"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"अॅप्लिकेशन"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"वाय-फाय डिरेक्ट"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"वाय-फाय थेट सुरू करा. हे वाय-फाय क्लायंट/हॉटस्पॉट बंद करेल."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"वाय-फाय डिरेक्ट कनेक्ट करू शकलो नाही."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"वाय-फाय डिरेक्ट चालू आहे"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"सेटिंग्जसाठी टॅप करा"</string>
     <string name="accept" msgid="1645267259272829559">"स्वीकार करा"</string>
     <string name="decline" msgid="2112225451706137894">"नकार द्या"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"आमंत्रण पाठविले"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"कनेक्ट करण्यासाठी आमंत्रण"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"प्रेषक:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रति:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्यक पिन टाइप करा:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"टॅबलेट <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ला कनेक्‍ट केलेले असताना तात्‍पुरते वाय-फाय वरून डिस्‍कनेक्‍ट होईल"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>शी तुमचे Android TV डिव्हाइस कनेक्ट केलेले असताना ते वाय-फाय वरून तात्पुरते डिस्कनेक्ट केले जाईल"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> वर फोन कनेक्ट केलेला असताना तो वाय-फाय वरून तात्पुरता डिस्कनेक्ट केला जाईल"</string>
     <string name="select_character" msgid="3365550120617701745">"वर्ण घाला"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS मेसेज पाठवत आहे"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; मोठ्या संख्येने SMS मेसेज पाठवत आहे. तुम्ही या अ‍ॅप ला मेसेज पाठविणे सुरु ठेवण्याची अनुमती देऊ इच्छिता?"</string>
@@ -1360,7 +1313,7 @@
     <string name="usb_accessory_notification_title" msgid="1785694450621427730">"USB अ‍ॅक्सेसरी कनेक्ट केली आहे"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"अधिक पर्यायांसाठी टॅप करा."</string>
     <string name="usb_power_notification_message" msgid="4647527153291917218">"चार्जर लावलेले डिव्हाइस. आणखी पर्यायांसाठी टॅप करा"</string>
-    <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"अॅनालॉग ऑडिओ अॅक्‍सेसरी आढळली"</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="3529881374464628084">"ॲनालॉग ऑडिओ ॲक्‍सेसरी आढळली"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="6309553946441565215">"या फोनसह संलग्‍न केलेले डीव्‍हाइस सुसंगत नाही. अधिक जाणून घेण्‍यासाठी टॅप करा."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबगिंग कनेक्‍ट केले"</string>
     <string name="adb_active_notification_message" msgid="7463062450474107752">"USB डीबगिंग बंद करण्यासाठी टॅप करा"</string>
@@ -1387,8 +1340,8 @@
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"इतर अ‍ॅप्सवर दाखवा"</string>
-    <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर प्रदर्शित करत आहे"</string>
-    <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्‍य अॅप्सवर प्रदर्शित करत आहे"</string>
+    <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर ॲप्सवर प्रदर्शित करत आहे"</string>
+    <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्‍य ॲप्सवर प्रदर्शित करत आहे"</string>
     <string name="alert_windows_notification_message" msgid="8917232109522912560">"<xliff:g id="NAME">%s</xliff:g> ने हे वैशिष्ट्य वापरू नये असे तुम्ही इच्छित असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
     <string name="alert_windows_notification_turn_off_action" msgid="2902891971380544651">"बंद करा"</string>
     <string name="ext_media_checking_notification_title" msgid="4411133692439308924">"<xliff:g id="NAME">%s</xliff:g> तपासत आहे…"</string>
@@ -1431,7 +1384,7 @@
     <string name="ext_media_status_ejecting" msgid="5463887263101234174">"बाहेर काढत आहे…"</string>
     <string name="ext_media_status_formatting" msgid="1085079556538644861">"फॉर्मेट करत आहे..."</string>
     <string name="ext_media_status_missing" msgid="5638633895221670766">"घातले नाही"</string>
-    <string name="activity_list_empty" msgid="1675388330786841066">"कोणत्याही जुळणाऱ्या अॅक्टिव्हिटी आढळल्या नाहीत."</string>
+    <string name="activity_list_empty" msgid="1675388330786841066">"कोणत्याही जुळणाऱ्या ॲक्टिव्हिटी आढळल्या नाहीत."</string>
     <string name="permlab_route_media_output" msgid="6243022988998972085">"मीडिया आउटपुट मार्गस्थ करा"</string>
     <string name="permdesc_route_media_output" msgid="4932818749547244346">"अन्य बाह्य डिव्हाइसेसवरील रूट मीडिया आउटपुट वर अनुप्रयोगास अनुमती देते."</string>
     <string name="permlab_readInstallSessions" msgid="3713753067455750349">"स्‍थापना सत्र वाचा"</string>
@@ -1441,7 +1394,7 @@
     <string name="permlab_requestDeletePackages" msgid="1703686454657781242">"पॅकेज हटवण्याची विनंती"</string>
     <string name="permdesc_requestDeletePackages" msgid="3406172963097595270">"अनुप्रयोगास पॅकेज हटवण्यासाठी विनंती करण्याची अनुमती देते."</string>
     <string name="permlab_requestIgnoreBatteryOptimizations" msgid="8021256345643918264">"बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यास सांगा"</string>
-    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"त्या अॅपसाठी बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यासाठी अॅपला परवानगी मागण्याची अनुमती देते."</string>
+    <string name="permdesc_requestIgnoreBatteryOptimizations" msgid="8359147856007447638">"त्या ॲपसाठी बॅटरी ऑप्टिमायझेशन दुर्लक्षित करण्‍यासाठी ॲपला परवानगी मागण्याची अनुमती देते."</string>
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"झूम नियंत्रणासाठी दोनदा टॅप करा"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"विजेट जोडू शकलो नाही."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"जा"</string>
@@ -1485,7 +1438,7 @@
     <string name="reset" msgid="2448168080964209908">"रीसेट करा"</string>
     <string name="submit" msgid="1602335572089911941">"सबमिट करा"</string>
     <string name="car_mode_disable_notification_title" msgid="5704265646471239078">"ड्रायव्हिंग अ‍ॅप चालू आहे"</string>
-    <string name="car_mode_disable_notification_message" msgid="7647248420931129377">"ड्रायव्हिंग अॅपमधून बाहेर पाडण्यासाठी टॅप करा."</string>
+    <string name="car_mode_disable_notification_message" msgid="7647248420931129377">"ड्रायव्हिंग ॲपमधून बाहेर पाडण्यासाठी टॅप करा."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"टेदरिंग किंवा हॉटस्पॉट सक्रिय"</string>
     <string name="tethered_notification_message" msgid="2113628520792055377">"सेट करण्यासाठी टॅप करा."</string>
     <string name="disable_tether_notification_title" msgid="7526977944111313195">"टेदरिंग बंद आहे"</string>
@@ -1590,7 +1543,7 @@
     <string name="sha256_fingerprint" msgid="4391271286477279263">"SHA-256 फिंगरप्रिंट:"</string>
     <string name="sha1_fingerprint" msgid="7930330235269404581">"SHA-1 फिंगरप्रिंट:"</string>
     <string name="activity_chooser_view_see_all" msgid="4292569383976636200">"सर्व पहा"</string>
-    <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"अॅक्टिव्हिटी निवडा"</string>
+    <string name="activity_chooser_view_dialog_title_default" msgid="4710013864974040615">"ॲक्टिव्हिटी निवडा"</string>
     <string name="share_action_provider_share_with" msgid="5247684435979149216">"यांच्यासह शेअर करा"</string>
     <string name="sending" msgid="3245653681008218030">"पाठवित आहे..."</string>
     <string name="launchBrowserDefault" msgid="2057951947297614725">"ब्राउझर लाँच करायचा?"</string>
@@ -1692,7 +1645,7 @@
     <string name="owner_name" msgid="2716755460376028154">"मालक"</string>
     <string name="error_message_title" msgid="4510373083082500195">"एरर"</string>
     <string name="error_message_change_not_allowed" msgid="1238035947357923497">"या बदलास आपल्या प्रशासकाद्वारे अनुमती नाही"</string>
-    <string name="app_not_found" msgid="3429141853498927379">"ही क्रिया हाताळण्यासाठी कोणताही अॅप्लिकेशन आढळला नाही"</string>
+    <string name="app_not_found" msgid="3429141853498927379">"ही क्रिया हाताळण्यासाठी कोणताही ॲप्लिकेशन आढळला नाही"</string>
     <string name="revoke" msgid="5404479185228271586">"मागे घ्‍या"</string>
     <string name="mediasize_iso_a0" msgid="1994474252931294172">"ISO A0"</string>
     <string name="mediasize_iso_a1" msgid="3333060421529791786">"ISO A1"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"बॅटरी सेव्‍हर हे वैशिष्ट्य बॅटरीचे आयुष्य वाढवण्‍यासाठी बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि इतर हाय-पॉवर वैशिष्ट्ये बंद किंवा मर्यादित करते. "<annotation id="url">"अधिक जाणून घ्या"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर बॅकग्राउंड अ‍ॅक्टिव्हिटी, काही व्हिज्युअल इफेक्ट आणि इतर हाय-पॉवर वैशिष्ट्ये बंद किंवा मर्यादित करतो."</string>
+    <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>
@@ -1973,7 +1926,7 @@
     <string name="autofill_save_type_payment_card" msgid="446631844461198737">"पेमेंट कार्ड"</string>
     <string name="autofill_save_type_generic_card" msgid="5898375974937018019">"कार्ड"</string>
     <string name="autofill_save_type_username" msgid="239040540379769562">"वापरकर्तानाव"</string>
-    <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ईमेल अॅड्रेस"</string>
+    <string name="autofill_save_type_email_address" msgid="5752949432129262174">"ईमेल ॲड्रेस"</string>
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"शांत रहा आणि जवळपास निवारा शोधा."</string>
     <string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"किनारपट्टीचे प्रदेश आणि नदीकाठची क्षेत्रे त्वरित रिकामी करून उंच मैदानासारख्या अधिक सुरक्षित ठिकाणी जा."</string>
     <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"शांत रहा आणि जवळपास निवारा शोधा."</string>
@@ -2015,7 +1968,7 @@
     <string name="standby_warning_message" product="default" msgid="5222741828239073484">"डिव्हाइस लवकरच बंद होणार आहे; सुरू ठेवण्यासाठी दाबा."</string>
     <string name="notification_appops_camera_active" msgid="5050283058419699771">"कॅमेरा"</string>
     <string name="notification_appops_microphone_active" msgid="4335305527588191730">"मायक्रोफोन"</string>
-    <string name="notification_appops_overlay_active" msgid="633813008357934729">"तुमच्‍या स्‍क्रीनवर इतर अॅप्‍सवर डिस्‍प्‍ले करत आहे"</string>
+    <string name="notification_appops_overlay_active" msgid="633813008357934729">"तुमच्‍या स्‍क्रीनवर इतर ॲप्‍सवर डिस्‍प्‍ले करत आहे"</string>
     <string name="dynamic_mode_notification_channel_name" msgid="2348803891571320452">"दिनक्रम मोडची माहिती सूचना"</string>
     <string name="dynamic_mode_notification_title" msgid="508815255807182035">"चार्जिंगची सामान्य पातळी गाठेपर्यंत कदाचित बॅटरी संपू शकते"</string>
     <string name="dynamic_mode_notification_summary" msgid="2541166298550402690">"बॅटरी लाइफ वाढवण्यासाठी बॅटरी सेव्हर सुरू केला आहे"</string>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 bfe6f2b..0c881c5 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Bunyi penggera"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bunyi pemberitahuan"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Tidak diketahui"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Rangkaian Wi-Fi tersedia</item>
-      <item quantity="one">Rangkaian Wi-Fi tersedia</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Rangkaian Wi-Fi terbuka tersedia</item>
-      <item quantity="one">Rangkaian Wi-Fi terbuka tersedia</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Sambung ke rangkaian Wi-Fi terbuka"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Menyambung ke rangkaian Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Disambungkan ke rangkaian Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Tidak dapat menyambung ke rangkaian Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Ketik untuk melihat semua rangkaian"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Sambung"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Semua rangkaian"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Benarkan rangkaian Wi-Fi yang dicadangkan?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Rangkaian yang dicadangkan oleh <xliff:g id="NAME">%s</xliff:g>. Peranti mungkin disambungkan secara automatik."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Benarkan"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Tidak perlu"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi akan dihidupkan secara automatik"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Apabila anda berada berdekatan dengan rangkaian disimpan yang berkualiti tinggi"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Jangan hidupkan kembali"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi dihidupkan secara automatik"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Anda berada berdekatan rangkaian yang disimpan: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Log masuk ke rangkaian Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Log masuk ke rangkaian"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Disambungkan"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> mempunyai kesambungan terhad"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ketik untuk menyambung juga"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Perubahan kepada tetapan tempat liputan anda"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Jalur tempat liputan anda telah berubah."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Peranti ini tidak menyokong pilihan anda untuk 5GHz sahaja. Sebaliknya, peranti ini akan menggunakan jalur 5GHz apabila tersedia."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Beralih kepada <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Peranti menggunakan <xliff:g id="NEW_NETWORK">%1$s</xliff:g> apabila <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tiada akses Internet. Bayaran mungkin dikenakan."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Beralih daripada <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kepada <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"jenis rangkaian tidak diketahui"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" mempunyai sambungan internet yang kurang baik."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Benarkan sambungan?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikasi %1$s ingin menyambung ke Rangkaian Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Satu aplikasi"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulakan Wi-Fi Langsung."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Ketik untuk mendapatkan tetapan"</string>
     <string name="accept" msgid="1645267259272829559">"Terima"</string>
     <string name="decline" msgid="2112225451706137894">"Tolak"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Jemputan dihantar"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Jemputan untuk menyambung"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Daripada:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Sambungan tablet ke Wi-Fi akan diputuskan buat sementara waktu semasa tablet bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Peranti Android TV anda akan diputuskan sambungan daripada Wi-Fi untuk sementara waktu semasa peranti ini disambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Sambungan telefon ke Wi-Fi akan diputuskan buat sementara waktu semasa telefon bersambung ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sedang menghantar banyak mesej SMS. Adakah anda mahu membenarkan apl ini terus menghantar mesej?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Penjimat Bateri mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual &amp; ciri kuasa tinggi yang lain untuk memanjangkan hayat bateri. "<annotation id="url">"Ketahui Lebih Lanjut"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Penjimat Bateri mematikan atau mengehadkan aktiviti latar belakang, sesetengah kesan visual &amp; ciri kuasa tinggi yang lain untuk memanjangkan hayat bateri."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 d7375e2..f5745b5 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"နှိုးစက်သံ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"အကြောင်းကြားချက်အသံ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"အမျိုးအမည်မသိ"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်</item>
-      <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Wi-Fi ကွန်ယက်များရရှိနိုင်သည်အား ဖွင့်ပါ</item>
-      <item quantity="one">Wi-Fi ကွန်ယက်ရရှိနိုင်သည်အား ဖွင့်ပါ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"အများသုံး Wi‑Fi ကွန်ရက်သို့ ချိတ်ဆက်ပါ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi ကွန်ရက်သို့ ချိတ်ဆက်နေသည်"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi ကွန်ရက်သို့ ချိတ်ဆက်ပြီးပါပြီ"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi ကွန်ရက်သို့ ချိတ်ဆက်၍ မရပါ"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ကွန်ရက်အားလုံးကို ကြည့်ရန် တို့ပါ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"ချိတ်ဆက်ရန်"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ကွန်ရက်အားလုံး"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"အကြံပြုထားသည့် Wi‑Fi ကွန်ရက်များ ခွင့်ပြုမလား။"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> သည် ကွန်ရက်များကို အကြံပြုထားသည်။ စက်သည် အလိုအလျောက် ချိတ်ဆက်နိုင်သည်။"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ခွင့်ပြုရန်"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"မလိုပါ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi ကို အလိုအလျောက်​ ပြန်ဖွင့်ပေးလိမ့်ပါမည်"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"သိမ်းဆည်းထားသည့် အရည်အသွေးမြင့်ကွန်ရက်များအနီးသို့ ရောက်ရှိသည့်အခါ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ပြန်မဖွင့်ပါနှင့်"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ကို အလိုအလျောက် ဖွင့်ထားသည်"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"သင်သည် သိမ်းထားသည့် ကွန်ရက်အနီးတွင် ရှိသည်− <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ဝိုင်ဖိုင်ကွန်ရက်သို့ လက်မှတ်ထိုးဝင်ပါ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ကွန်ယက်သို့ လက်မှတ်ထိုးဝင်ရန်"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ချိတ်ဆက်ထားသည်"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> တွင် ချိတ်ဆက်မှုကို ကန့်သတ်ထားသည်"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"မည်သို့ပင်ဖြစ်စေ ချိတ်ဆက်ရန် တို့ပါ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"သင်၏ဟော့စပေါ့ ဆက်တင်များ ပြောင်းလဲမှု"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"သင်၏ ဟော့စပေါ့လိုင်း ပြောင်းသွားပါပြီ။"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ဤစက်ပစ္စည်းသည် သင်၏ 5GHz သီးသန့်ရွေးချယ်မှုအတွက် ပံ့ပိုးမထားပါ။ ၎င်းအစား ဤစက်ပစ္စည်းသည် ရနိုင်သည့်အခါ 5GHz လိုင်းကို သုံးသွားပါမည်။"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ဖြင့် အင်တာနက် အသုံးမပြုနိုင်သည့်အချိန်တွင် စက်ပစ္စည်းသည် <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ကို သုံးပါသည်။ ဒေတာသုံးစွဲခ ကျသင့်နိုင်ပါသည်။"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> မှ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> သို့ ပြောင်းလိုက်ပြီ"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"အမည်မသိကွန်ရက်အမျိုးအစား"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ဝိုင်ဖိုင်ကိုချိတ်ဆက်မရပါ"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ချိတ်ဆက်မှုကို ခွင့်ပြုမလား?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"အပလီကေးရှင်း %1$s သည် ဝိုင်ဖိုင်ကွန်ရက် %2$s ကိုချိတ်ဆက်လိုသည်"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"အပလီကေးရှင်း"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"တိုက်ရိုက် Wi-Fi"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"တိုက်ရိုက်Wi-Fi ကို စတင်ပါ။ ၎င်းသည် Wi-Fi  ဟော့စပေါ့ကို ရပ်ဆိုင်းစေမှာ ဖြစ်ပါသည်။"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"တိုက်ရိုက်ဝိုင်ဖိုင်ကို စတင်လို့ မရပါ"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi  တိုက်ရိုက် ကိုဖွင့်ထားသည်"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ဆက်တင်များအတွက် တို့ပါ"</string>
     <string name="accept" msgid="1645267259272829559">"လက်ခံရန်"</string>
     <string name="decline" msgid="2112225451706137894">"လက်မခံပါ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ဖိတ်ကြားချက် ပို့ပြီး"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ချိတ်ဆက်ရန် ဖိတ်ကြားချက်"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"မှ၊"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"သို့:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"လိုအပ်သော ပင် နံပါတ် ရိုက်ရန်:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ပင် နံပါတ်:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> နှင့် ဆက်သွယ်ထားစဉ် တက်ဘလက်ဟာ Wi-Fi  နှင့် ဆက်သွယ်မှု ရပ်ဆိုင်းထားမှာ ဖြစ်ပါတယ်"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"သင်၏ Android TV စက်ပစ္စည်းသည် <xliff:g id="DEVICE_NAME">%1$s</xliff:g> သို့ ချိတ်ဆက်ထားသည့်အခါ Wi-Fi မှနေ၍ ယာယီ ချိတ်ဆက်မှုဖြုတ်သွားပါမည်။"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို ဆက်သွယ်ထားစဉ် ဖုန်းအား ဝိုင်ဖိုင်မှ ဆက်သွယ်မှု ရပ်ဆိုင်းထားပါမည်"</string>
     <string name="select_character" msgid="3365550120617701745">"စာရိုက်ထည့်ရန်"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"စာတိုပို့စနစ်(SMS)ဖြင့် စာများ ပို့သည်"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; မှ စာ အမြောက်အများ ပို့နေပါသည်။ ဒီအပလီကေးရှင်းကို ဆက်လက်ပြီး လုပ်ဆောင်ရန် ခွင့်ပြုပါမလား"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က နောက်ခံလုပ်ဆောင်ချက်၊ အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် အခြား ပါဝါအလွန်သုံးသော ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။ "<annotation id="url">"ပိုမိုလေ့လာရန်"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ဘက်ထရီသက်တမ်း ပိုရှည်စေရန် \'ဘက်ထရီအားထိန်း\' က နောက်ခံလုပ်ဆောင်ချက်၊ အချို့ အမြင်အာရုံဆိုင်ရာ အထူးပြုလုပ်ချက်များနှင့် အခြား ပါဝါအလွန်သုံးသော ဝန်ဆောင်မှုများကို ပိတ်ခြင်း သို့မဟုတ် ကန့်သတ်ခြင်းတို့ ပြုလုပ်သည်။"</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 3a78f79..0359779 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmlyder"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Varsellyder"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Ukjent"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi-nettverk er tilgjengelig</item>
-      <item quantity="one">Wi-Fi-nettverk er tilgjengelig</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Åpne Wi-Fi-nettverk er tilgjengelig</item>
-      <item quantity="one">Åpent Wi-Fi-nettverk er tilgjengelig</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Koble til et åpent Wi‑Fi-nettverk"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Kobler til Wi-Fi-nettverket"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Koblet til Wi-Fi-nettverk"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Kunne ikke koble til Wi-Fi-nettverket"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Trykk for å se alle nettverkene"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Koble til"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alle nettverk"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vil du tillate foreslåtte Wi-Fi nettverk?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g>-foreslåtte nettverk. Enheten kan koble til automatisk."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Tillat"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nei takk"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi slås på automatisk"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Når du er i nærheten av et lagret nettverk av høy kvalitet"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ikke slå på igjen"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi er slått på automatisk"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Du er i nærheten av et lagret nettverk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logg på Wi-Fi-nettverket"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Logg på nettverk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Tilkoblet"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begrenset tilkobling"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Trykk for å koble til likevel"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Endres til innstillingene dine for Wi-Fi-soner"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Båndet ditt for Wi-Fi-sone er endret."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Denne enheten støtter ikke innstillingen din for bare 5 GHz. I stedet bruker enheten 5 GHz-båndet når det er tilgjengelig."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Byttet til <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Enheten bruker <xliff:g id="NEW_NETWORK">%1$s</xliff:g> når <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ikke har Internett-tilgang. Avgifter kan påløpe."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byttet fra <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> til <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en ukjent nettverkstype"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dårlig internettilkobling."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vil du tillat tilkoblingen?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vil koble til Wi-Fi-nettverket %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kunne ikke starte Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Trykk for å få innstillinger"</string>
     <string name="accept" msgid="1645267259272829559">"Godta"</string>
     <string name="decline" msgid="2112225451706137894">"Avslå"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitasjonen er sendt"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitasjon for tilkobling"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Fra:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Nettbrettet frakobles Wi-Fi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV-enheten din blir midlertidig koblet fra Wi-Fi mens den er koblet til <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonen frakobles Wi-Fi midlertidig mens den er tilkoblet <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; sender et stort antall SMS. Vil du la appen fortsette å sende ut meldinger?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Batterisparing slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner med høyt strømforbruk for å forlenge batterilevetiden. "<annotation id="url">"Finn ut mer"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Batterisparing slår av eller begrenser bakgrunnsaktivitet, enkelte visuelle effekter og andre funksjoner med høyt strømforbruk for å forlenge batterilevetiden."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 d3eb0c3..2617086 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1250,30 +1250,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"अलार्मका आवाजहरू"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"सूचना सम्बन्धी आवाजहरू"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"अज्ञात"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
-      <item quantity="one">Wi-Fi सञ्जाल उपलब्ध छ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other"> खुल्ला Wi-Fi सञ्जालहरू उपलब्ध छन्</item>
-      <item quantity="one">खुल्ला Wi-Fi सञ्जाल उपलब्ध छ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"खुला Wi‑Fi नेटवर्कमा जडान गर्नुहोस्"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi नेटवर्कमा जडान गर्दै"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi नेटवर्कमा जडान गरियो"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi नेटवर्कमा जडान गर्न सकिएन"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"सबै नेटवर्कहरू हेर्न ट्याप गर्नुहोस्"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"जडान गर्नुहोस्"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"सबै नेटवर्कहरू"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"सिफारिस गरिएका Wi‑Fi नेटवर्कहरूलाई अनुमति दिनुहोस्?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ले सिफारिस गरेका नेटवर्कहरू। यन्त्र स्वतः जडान हुन सक्छ।"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"अनुमति दिनुहोस्"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"पर्दैन, धन्यवाद"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi स्वतः सक्रिय हुनेछ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"तपाईं कुनै सुरक्षित गरिएको उच्च गुणस्तरीय नेटवर्कको नजिक हुनुभएको अवस्थामा"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"फेरि सक्रिय नगर्नुहोला"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi स्वतः सक्रिय गरियो"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"तपाईं कुनै सुरक्षित गरिएको नेटवर्क नजिकै हुनुहुन्छ: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi नेटवर्कमा साइन इन गर्नुहोस्"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"सञ्जालमा साइन इन गर्नुहोस्"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1286,9 +1262,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"जोडियो"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> को जडान सीमित छ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"जसरी भए पनि जडान गर्न ट्याप गर्नुहोस्"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"तपाईंको हटस्पट सेटिङहरूमा परिवर्तन हुन्छ"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"तपाईंको हटस्पट ब्यान्ड परिवर्तन भएको छ।"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"यो यन्त्रले तपाईंको 5GHz मात्रको प्राथमिकतालाई समर्थन गर्दैन। बरु, उपलब्ध भएको खण्डमा यो यन्त्रले 5GHz ब्यान्ड प्रयोग गर्छ।"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> मा बदल्नुहोस्"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> मार्फत इन्टरनेटमाथि पहुँच राख्न नसकेको अवस्थामा यन्त्रले <xliff:g id="NEW_NETWORK">%1$s</xliff:g> प्रयोग गर्दछ। शुल्क लाग्न सक्छ।"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> बाट <xliff:g id="NEW_NETWORK">%2$s</xliff:g> मा परिवर्तन गरियो"</string>
@@ -1300,27 +1273,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"नेटवर्कको कुनै अज्ञात प्रकार"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"वाइ-फाइसँग जडान गर्न सकेन"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" खराब इन्टरनेट जडान रहेको छ।"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"जडान अनुमति दिने हो?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"अनुप्रयोग %1$s Wifi सञ्जाल %2$s मा जडान गर्न चाहन्छ"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"एउटा अनुप्रयोग"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi प्रत्यक्ष"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi सीधा सुरु गर्नुहोस्। यसले Wi-Fi ग्राहक/हट्स्पटलाई बन्द गराउने छ।"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi सीधा सुरु हुन सकेन।"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष खुल्ला छ"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"सेटिङहरूका लागि ट्याप गर्नुहोस्"</string>
     <string name="accept" msgid="1645267259272829559">"स्वीकार्नुहोस्"</string>
     <string name="decline" msgid="2112225451706137894">"अस्वीकार गर्नुहोस्"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"निमन्त्रणा पठाइएको"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"जडानमा निमन्त्रणा"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"बाट:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रापक:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्यक PIN टाइप गर्नुहोस्:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"यो <xliff:g id="DEVICE_NAME">%1$s</xliff:g>सँग जोडिएको बेला ट्याब्लेट अस्थायी रूपमा वाइ-फाइबाट विच्छेद गरिने छ।"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"तपाईंको Android TV यन्त्र <xliff:g id="DEVICE_NAME">%1$s</xliff:g> मा जोडिएको बेला यो केही समयका लागि Wi-Fi बाट विच्छेद हुने छ।"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"जब यो <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग जडित हुन्छ, फोन अस्थायी रूपमा वाइ-फाइबाट विच्छेद हुने छ"</string>
     <string name="select_character" msgid="3365550120617701745">"अक्षरहरू प्रवेश गराउनुहोस्"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS सन्देशहरू पठाइँदै"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ले धरै संख्यामा SMS सन्देशहरू पठाउँदैछ। के तपाईं यस अनुप्रयोगलाई सन्देशहरू पठाउन सुचारु गर्न अनुमति दिन चाहनु हुन्छ?"</string>
@@ -1823,8 +1777,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ब्याट्री सेभरले ब्याट्रीको आयु लामो बनाउन पृष्ठभूमिका गतिविधि, कतिपय भिजुअल प्रभावहरू तथा उच्च पावर प्रयोग गर्ने अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ। "<annotation id="url">"थप जान्नुहोस्"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ब्याट्री सेभरले ब्याट्रीको आयु लामो बनाउन पृष्ठभूमिका गतिविधि, कतिपय भिजुअल प्रभावहरू तथा उच्च पावर प्रयोग गर्ने अन्य सुविधाहरू निष्क्रिय वा सीमित पार्छ।"</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2057,4 +2013,23 @@
     </plurals>
     <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 9300f74..43b4ede 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarmgeluiden"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Meldingsgeluiden"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Onbekend"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wifi-netwerken beschikbaar</item>
-      <item quantity="one">Wifi-netwerk beschikbaar</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Open wifi-netwerken beschikbaar</item>
-      <item quantity="one">Open wifi-netwerk beschikbaar</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Verbinding maken met een open wifi-netwerk"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Verbinden met wifi-netwerk"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Verbonden met een wifi-netwerk"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Kan geen verbinding maken met het wifi-netwerk"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tik om alle netwerken te bekijken"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Verbinding maken"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alle netwerken"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Voorgestelde wifi-netwerken toestaan?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> heeft netwerken voorgesteld. Apparaat kan automatisch verbinding maken."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Toestaan"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nee, bedankt"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wifi wordt automatisch ingeschakeld"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Wanneer je in de buurt van een opgeslagen netwerk van hoge kwaliteit bent"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Niet weer inschakelen"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wifi automatisch ingeschakeld"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Je bent in de buurt van een opgeslagen netwerk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Inloggen bij wifi-netwerk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Inloggen bij netwerk"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Verbonden"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> heeft beperkte connectiviteit"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tik om toch verbinding te maken"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Wijzigingen in je hotspot-instellingen"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Je hotspot-band is gewijzigd."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dit apparaat biedt geen ondersteuning voor je voorkeur voor alleen 5 GHz. In plaats daarvan gebruikt dit apparaat de 5-GHz-band wanneer deze beschikbaar is."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Overgeschakeld naar <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Apparaat gebruikt <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wanneer <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> geen internetverbinding heeft. Er kunnen kosten in rekening worden gebracht."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Overgeschakeld van <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> naar <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"een onbekend netwerktype"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met wifi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" heeft een slechte internetverbinding."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Verbinding toestaan?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"App %1$s wil verbinding maken met wifi-netwerk %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Een app"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wifi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kan Wifi Direct niet starten."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wifi Direct is actief"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tik voor instellingen"</string>
     <string name="accept" msgid="1645267259272829559">"Accepteren"</string>
     <string name="decline" msgid="2112225451706137894">"Weigeren"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging verzonden"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Uitnodiging om te koppelen"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Van:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Naar:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon is verbonden met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl het Android TV-apparaat is verbonden met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"De verbinding met het wifi-netwerk wordt tijdelijk uitgeschakeld terwijl de telefoon verbonden is met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; verzendt moment een groot aantal sms-berichten. Wil je toestaan ​​dat deze app berichten blijft verzenden?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Batterijbesparing beperkt de achtergrondactiviteit, bepaalde visuele effecten en andere functies die veel stroom kosten om de batterijduur te verlengen. "<annotation id="url">"Meer informatie"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Batterijbesparing beperkt de achtergrondactiviteit, bepaalde visuele effecten en andere functies die veel stroom kosten om de batterijduur te verlengen."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 cd36d53..68b76c8 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"ଆଲାରାମ୍ ଶବ୍ଦ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ବିଜ୍ଞପ୍ତି ଶବ୍ଦ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ଅଜଣା"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ</item>
-      <item quantity="one">ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କ ଉପଲବ୍ଧ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">ମୁକ୍ତ ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କଗୁଡ଼ିକ ଉପଲବ୍ଧ</item>
-      <item quantity="one">ମୁକ୍ତ ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କ ଉପଲବ୍ଧ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ୱାଇ‑ଫାଇ ନେଟୱର୍କ ଖୋଲିବାକୁ କନେକ୍ଟ କରନ୍ତୁ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କ ସହିତ କନେକ୍ଟ ହେଉଛି"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କରେ କନେକ୍ଟ ହୋଇଛି"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ୱାଇ-ଫାଇ ନେଟ୍‌ୱର୍କରେ କନେକ୍ଟ କରିହେଲା ନାହିଁ"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ସମସ୍ତ ନେଟ୍‌ୱର୍କ ଦେଖିବାକୁ ଟାପ୍‍ କରନ୍ତୁ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"କନେକ୍ଟ କରନ୍ତୁ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ସମସ୍ତ ନେଟ୍‌ୱର୍କ"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"ପ୍ରସ୍ତାବିତ ୱାଇ-ଫାଇ ନେଟ୍‌ୱାର୍କଗୁଡ଼ିକୁ ଅନୁମତି ଦେବେ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ପ୍ରସ୍ତାବିତ ନେଟ୍‌ୱାର୍କଗୁଡ଼ିକ। ଡିଭାଇସ୍ ହୁଏତ ସ୍ୱଚାଳିତ ଭାବେ ସଂଯୋଗ ହୋଇପାରେ।"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ଅନୁମତି ଦିଅନ୍ତୁ"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ନାହିଁ, ଥାଉ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ୱାଇ-ଫାଇ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍ ହେବ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ଆପଣ ଏକ ଉଚ୍ଚ-କ୍ୱାଲିଟୀ ବିଶିଷ୍ଟ ସେଭ୍‌ କରାଯାଇଥିବା ନେଟ୍‌ୱର୍କ ପାଖରେ ଥିବା ସମୟରେ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ପୁଣି ଅନ୍‍ କରନ୍ତୁ ନାହିଁ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ୱାଇ-ଫାଇ ସ୍ୱଚାଳିତ ଭାବେ ଅନ୍‍ ହେଲା"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ସେଭ୍ ହୋଇଥିବା ନେଟ୍‌ୱର୍କ ନିକଟରେ ଆପଣ ଅଛନ୍ତି: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ୱାଇ-ଫାଇ ନେଟୱର୍କରେ ସାଇନ୍‍-ଇନ୍‍ କରନ୍ତୁ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ନେଟ୍‌ୱର୍କରେ ସାଇନ୍‍ ଇନ୍‍ କରନ୍ତୁ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ସଂଯୁକ୍ତ ହୋଇଛି"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>ର ସୀମିତ ସଂଯୋଗ ଅଛି"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ତଥାପି ଯୋଗାଯୋଗ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ଆପଣଙ୍କର ହଟ୍‌ସ୍ପଟ୍‍ ସେଟିଙ୍ଗକୁ ବଦଳିଯାଇଛି"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ଆପଣଙ୍କର ହଟ୍‍ସ୍ପଟ୍‌ ପରିବର୍ତ୍ତନ କରାଯାଇଛି"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"କେବଳ 5GHz ପାଇଁ, ଏହି ଡିଭାଇସ୍‍ ଆପଣଙ୍କର ପସନ୍ଦକୁ ସପୋର୍ଟ କରେନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ, ଏହି ଡିଭାଇସ୍‍ 5GHz ବ୍ୟାଣ୍ଡ ବ୍ୟବହାର କରିବ।"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>ର ଇଣ୍ଟରନେଟ୍‍ ଆକ୍ସେସ୍ ନଥିବାବେଳେ ଡିଭାଇସ୍‍ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ବ୍ୟବହାର କରିଥାଏ। ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ।"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ରୁ <xliff:g id="NEW_NETWORK">%2$s</xliff:g>କୁ ବଦଳାଗଲା"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ଏକ ଅଜଣା ନେଟ୍‌ୱର୍କ ପ୍ରକାର"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ୱାଇ-ଫାଇ ସହ ସଂଯୋଗ ହୋଇପାରିଲା ନାହିଁ"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ଏହାର ଦୁର୍ବଳ ଇଣ୍ଟରନେଟ୍‍ ସଂଯୋଗ ରହିଛି।"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ସଂଯୋଗର ଅନୁମତି ଦେବେ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ଆପ୍ଲିକେଶନ୍‍ %1$s %2$s ୱାଇ-ଫାଇ ନେଟୱର୍କକୁ ସଂଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ଏକ ଅନୁପ୍ରୟୋଗ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଆରମ୍ଭ କରନ୍ତୁ। ଏହା ୱାଇ-ଫାଇ କ୍ଲାଏଣ୍ଟ/ହଟସ୍ପଟ୍‍କୁ ବନ୍ଦ କରିଦେବ।"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଆରମ୍ଭ କରିପାରିଲା ନାହିଁ।"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ୱାଇ-ଫାଇ ଡାଇରେକ୍ଟ ଅନ୍‍ ଅଛି"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ସେଟିଙ୍ଗ ପାଇଁ ଟାପ୍‍ କରନ୍ତୁ"</string>
     <string name="accept" msgid="1645267259272829559">"ସ୍ୱୀକାର କରନ୍ତୁ"</string>
     <string name="decline" msgid="2112225451706137894">"ପ୍ରତ୍ୟାଖ୍ୟାନ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ନିମନ୍ତ୍ରଣ ପଠାଗଲା"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ସଂଯୁକ୍ତ ହେବାକୁ ନିମନ୍ତ୍ରଣ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ପ୍ରେରକ:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ପ୍ରାପ୍ତେଷୁ:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ଆବଶ୍ୟକ PIN ଟାଇପ୍‍ କରନ୍ତୁ:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୁକ୍ତ ହୋଇଥିବାବେଳେ, ୱାଇ-ଫାଇଠାରୁ ଟାବଲେଟ୍‍ଟି ଅସ୍ଥାୟୀ ଭାବେ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ଆପଣଙ୍କର Android ଟିଭି ଡିଭାଇସ୍ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ହେଉଥିବା ସମୟରେ ୱାଇ-ଫାଇରୁ ଅସ୍ଥାୟୀ ଭାବେ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ସହ ସଂଯୋଗ ଥିବାବେଳେ ଫୋନ୍‌ଟି ୱାଇ-ଫାଇରୁ ଅସ୍ଥାୟୀ ଭାବରେ ବିଚ୍ଛିନ୍ନ ହେବ"</string>
     <string name="select_character" msgid="3365550120617701745">"ବର୍ଣ୍ଣ ଲେଖନ୍ତୁ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS ମେସେଜ୍‌ଗୁଡ଼ିକୁ ପଠାଯାଉଛି"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ବହୁତ ସଂଖ୍ୟାର SMS ମେସେଜ୍‍ ପଠାଉଛି। ଏହି ଆପ୍‍ ମେସେଜ୍‍ ପଠାଇବା ଜାରି ରଖିବାକୁ ଆପଣ ଅନୁମତି ଦେବେ କି?"</string>
@@ -1817,8 +1771,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ବ୍ୟାଟେରୀ ସେଭର୍ ବ୍ୟାଟେରୀ ଜୀବନ ବଢ଼ାଇବାକୁ ପୃଷ୍ଟପଟ କାର୍ଯ୍ୟକଳାପ,କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବଗୁଡ଼ିକୁ &amp; ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ କରୁଥିବା ଅନ୍ୟ ବୈଶିଷ୍ଟ୍ୟକୁ ବନ୍ଦ ରଖେ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ। "<annotation id="url">"ଅଧିକ ଜାଣନ୍ତୁ"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ବ୍ୟାଟେରୀ ସେଭର୍ ବ୍ୟାଟେରୀ ଜୀବନ ବଢ଼ାଇବାକୁ ପୃଷ୍ଟପଟ କାର୍ଯ୍ୟକଳାପକୁ,କିଛି ଭିଜୁଆଲ୍ ପ୍ରଭାବଗୁଡ଼ିକୁ &amp; ବ୍ୟାଟେରୀ ଅଧିକ ଖର୍ଚ୍ଚ କରୁଥିବା ଅନ୍ୟ ବୈଶିଷ୍ଟ୍ୟକୁ ବନ୍ଦ ରଖେ କିମ୍ବା ପ୍ରତିବନ୍ଧିତ କରିଥାଏ।"</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 68cfc5f..63b5f53 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"ਅਲਾਰਮ ਧੁਨੀਆਂ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"ਸੂਚਨਾ ਧੁਨੀਆਂ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ਅਗਿਆਤ"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ</item>
-      <item quantity="other">ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">ਉਪਲਬਧ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
-      <item quantity="other">ਉਪਲਬਧ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਖੋਲ੍ਹੋ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"ਖੁੱਲ੍ਹੇ ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਹੋਵੋ"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ਵਾਈ‑ਫਾਈ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"ਸਾਰੇ ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"ਕਨੈਕਟ ਕਰੋ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"ਸਾਰੇ ਨੈੱਟਵਰਕ"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"ਕੀ ਸੁਝਾਏ ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ ਵਰਤਣੇ ਹਨ?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> ਦੇ ਸੁਝਾਏ ਨੈੱਟਵਰਕ। ਸ਼ਾਇਦ ਡੀਵਾਈਸ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਕਨੈਕਟ ਹੋਵੇ।"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ਵਰਤਣ ਦਿਓ"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"ਵਾਈ‑ਫਾਈ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਚੱਲ ਪਵੇਗਾ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ਜਦੋਂ ਤੁਸੀਂ ਕਿਸੇ ਰੱਖਿਅਤ ਕੀਤੇ ਉੱਚ-ਗੁਣਵੱਤਾ ਵਾਲੇ ਨੈੱਟਵਰਕ ਦੇ ਨੇੜੇ ਹੋਵੋ"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ਵਾਪਸ ਚਾਲੂ ਨਾ ਕਰੋ"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"ਵਾਈ‑ਫਾਈ ਨੂੰ ਸਵੈਚਲਿਤ ਤੌਰ \'ਤੇ ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ਤੁਸੀਂ ਕਿਸੇ ਰੱਖਿਅਤ ਕੀਤੇ ਨੈੱਟਵਰਕ ਦੇ ਨੇੜੇ ਹੋ: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ਨੈੱਟਵਰਕ \'ਤੇ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"ਕਨੈਕਟ ਹੋਏ"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ਕੋਲ ਸੀਮਤ ਕਨੈਕਟੀਵਿਟੀ ਹੈ"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ਫਿਰ ਵੀ ਕਨੈਕਟ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ਤੁਹਾਡੀਆਂ ਹੌਟਸਪੌਟ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਬਦਲਾਅ"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ਤੁਹਾਡਾ ਹੌਟਸਪੌਟ ਬੈਂਡ ਬਦਲ ਗਿਆ ਹੈ।"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ਇਹ ਡੀਵਾਈਸ ਸਿਰਫ਼ 5GHz ਦੀ ਤੁਹਾਡੀ ਤਰਜੀਹ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ ਹੈ। ਇਸਦੀ ਬਜਾਏ, ਇਹ ਡੀਵਾਈਸ ਉਪਲਬਧ ਹੋਣ \'ਤੇ 5GHz ਬੈਂਡ ਵਰਤੇਗਾ।"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"ਬਦਲਕੇ <xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ਲਿਆਂਦਾ ਗਿਆ"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ਦੀ ਇੰਟਰਨੈੱਟ \'ਤੇ ਪਹੁੰਚ ਨਾ ਹੋਣ \'ਤੇ ਡੀਵਾਈਸ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ। ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ।"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ਤੋਂ ਬਦਲਕੇ <xliff:g id="NEW_NETWORK">%2$s</xliff:g> \'ਤੇ ਕੀਤਾ ਗਿਆ"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ਇੱਕ ਅਗਿਆਤ ਨੈੱਟਵਰਕ ਕਿਸਮ"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ਵਾਈ-ਫਾਈ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਹੋ ਸਕਿਆ"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"ਕੀ ਕਨੈਕਸ਼ਨ ਦੀ ਆਗਿਆ ਦੇਣੀ ਹੈ?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"ਐਪਲੀਕੇਸ਼ਨ %1$s ਵਾਈ-ਫਾਈ ਨੈੱਟਵਰਕ %2$s ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ਇੱਕ ਐਪਲੀਕੇਸ਼ਨ"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi ਡਾਇਰੈਕਟ ਚਾਲੂ ਕਰੋ। ਇਹ ਵਾਈ-ਫਾਈ ਕਲਾਇੰਟ/ਹੌਟਸਪੌਟ ਨੂੰ ਬੰਦ ਕਰ ਦੇਵੇਗਾ।"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ ਚਾਲੂ ਨਹੀਂ ਹੋ ਸਕਿਆ।"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"ਵਾਈ-ਫਾਈ ਡਾਇਰੈਕਟ ਚਾਲੂ ਹੈ।"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ਸੈਟਿੰਗਾਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
     <string name="accept" msgid="1645267259272829559">"ਸਵੀਕਾਰ ਕਰੋ"</string>
     <string name="decline" msgid="2112225451706137894">"ਅਸਵੀਕਾਰ ਕਰੋ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ਸੱਦਾ ਭੇਜਿਆ"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ਕਨੈਕਟ ਕਰਨ ਲਈ ਸੱਦਾ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"ਇਸ ਤੋਂ:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ਵੱਲ:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"ਲੋੜੀਂਦਾ ਪਿੰਨ ਟਾਈਪ ਕਰੋ:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ਪਿੰਨ:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ਟੈਬਲੈੱਟ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਵੇਗਾ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ਤੁਹਾਡਾ Android TV ਡੀਵਾਈਸ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ \'ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ \'ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਵੇਗਾ"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ਫ਼ੋਨ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤੇ ਜਾਣ ਤੇ ਵਾਈ-ਫਾਈ ਤੋਂ ਅਸਥਾਈ ਤੌਰ ਤੇ ਡਿਸਕਨੈਕਟ ਹੋ ਜਾਏਗਾ"</string>
     <string name="select_character" msgid="3365550120617701745">"ਅੱਖਰ ਦਾਖਲ ਕਰੋ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS ਸੁਨੇਹੇ ਭੇਜ ਰਿਹਾ ਹੈ"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ਵੱਡੀ ਸੰਖਿਆ ਵਿੱਚ SMS ਸੁਨੇਹੇ ਭੇਜ ਰਿਹਾ ਹੈ। ਕੀ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸੁਨੇਹੇ ਭੇਜਣਾ ਜਾਰੀ ਰੱਖਣ ਦੀ ਆਗਿਆ ਦੇਣਾ ਚਾਹੁੰਦੇ ਹੋ?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"ਬੈਟਰੀ ਸੇਵਰ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ ਹੋਰ ਉੱਚ-ਪਾਵਰ ਵਾਲੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾ ਦਿੰਦਾ ਹੈ। "<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"ਬੈਟਰੀ ਸੇਵਰ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ ਅਤੇ ਹੋਰ ਉੱਚ-ਪਾਵਰ ਵਾਲੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾ ਦਿੰਦਾ ਹੈ।"</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 3be0900..bd695a9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Dźwięki alarmu"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Dźwięki powiadomień"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Nieznany"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="few">Dostępne są sieci Wi-Fi</item>
-      <item quantity="many">Dostępne są sieci Wi-Fi</item>
-      <item quantity="other">Dostępne są sieci Wi-Fi</item>
-      <item quantity="one">Dostępna jest sieć Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="few">Dostępne są otwarte sieci Wi-Fi</item>
-      <item quantity="many">Dostępne są otwarte sieci Wi-Fi</item>
-      <item quantity="other">Dostępne są otwarte sieci Wi-Fi</item>
-      <item quantity="one">Dostępna jest otwarta sieć Wi-Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Połącz się z otwartą siecią Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Łączę z siecią Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Połączono z siecią Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nie udało się połączyć z siecią Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Kliknij, by zobaczyć wszystkie sieci"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Połącz"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Wszystkie sieci"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Zezwalać na sugerowane sieci Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Sugerowane sieci: <xliff:g id="NAME">%s</xliff:g>. Urządzenie może łączyć się automatycznie."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Zezwól"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nie, dziękuję"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi włączy się automatycznie"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Gdy znajdziesz się w pobliżu zapisanej sieci o mocnym sygnale"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Nie włączaj ponownie"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi włączone automatycznie"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Jesteś w pobliżu zapisanej sieci: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Zaloguj się w sieci Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Zaloguj się do sieci"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Połączono"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ma ograniczoną łączność"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Kliknij, by mimo to nawiązać połączenie"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Zmieniono ustawienia hotspotu"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Zmieniono pasmo hotspotu."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"To urządzenie nie może korzystać tylko z częstotliwości 5 GHz. Będzie korzystać z tego pasma, jeśli będzie ono dostępne."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Zmieniono na połączenie typu <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Urządzenie korzysta z połączenia typu <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, gdy <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nie dostępu do internetu. Mogą zostać naliczone opłaty."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Przełączono z połączenia typu <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na <xliff:g id="NEW_NETWORK">%2$s</xliff:g>."</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"nieznany typ sieci"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ma powolne połączenie internetowe."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Zezwolić na połączenie?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacja %1$s chce połączyć się z siecią Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacja"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nie można uruchomić Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Kliknij, by wyświetlić ustawienia"</string>
     <string name="accept" msgid="1645267259272829559">"Akceptuj"</string>
     <string name="decline" msgid="2112225451706137894">"Odrzuć"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Wysłano zaproszenie"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Zaproszenie do połączenia"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Do:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tablet zostanie tymczasowo odłączony od Wi-Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Urządzenie z Androidem TV zostanie odłączone od sieci Wi-Fi na czas połączenia z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Na czas połączenia z <xliff:g id="DEVICE_NAME">%1$s</xliff:g> telefon zostanie tymczasowo odłączony od Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikacja &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; wysyła wiele SMS-ów. Chcesz pozwolić tej aplikacji dalej wysyłać SMS-y?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje intensywnie zużywające energię. "<annotation id="url">"Więcej informacji"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Aby wydłużyć czas pracy na baterii, Oszczędzanie baterii wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne oraz inne funkcje intensywnie zużywające energię."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 7442703..45a2abd2 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Redes Wi-Fi disponíveis</item>
-      <item quantity="other">Redes Wi-Fi disponíveis</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
-      <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conectar a uma rede Wi‑Fi aberta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Conectando-se à rede Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Conectado a uma rede Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Não foi possível conectar-se à rede Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toque para ver todas as redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectar"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas as redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Permitir redes Wi-Fi sugeridas?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Redes sugeridas pelo app <xliff:g id="NAME">%s</xliff:g>. O dispositivo pode se conectar automaticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Não"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"O Wi‑Fi será ativado automaticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quando você estiver perto de uma rede salva de alta qualidade"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Não ativar novamente"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ativado automaticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Você está perto de uma rede salva: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para conectar mesmo assim"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mudanças nas suas configurações de ponto de acesso"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Sua banda de ponto de acesso foi alterada."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma conexão de baixa qualidade com a Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toque para ver as configurações"</string>
     <string name="accept" msgid="1645267259272829559">"Aceitar"</string>
     <string name="decline" msgid="2112225451706137894">"Recusar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Convite para se conectar"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"O tablet desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"O dispositivo Android TV desconectará o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envia uma grande quantidade de mensagens SMS. Quer permitir que este app continue enviando mensagens?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 add12d9..0fd303f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons de alarme"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Redes Wi-Fi disponíveis</item>
-      <item quantity="one">Rede Wi-Fi disponível</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Redes Wi-Fi abertas disponíveis</item>
-      <item quantity="one">Rede Wi-Fi aberta disponível</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Ligar à rede Wi-Fi aberta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"A ligar à rede Wi-Fi…"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ligado à rede Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Não foi possível ligar à rede Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toque para ver todas as redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Ligar"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas as redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Pretende permitir redes Wi-Fi sugeridas?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Redes sugeridas por <xliff:g id="NAME">%s</xliff:g>. O dispositivo pode estabelecer ligação automaticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Não, obrigado"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"O Wi‑Fi será ativado automaticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quando estiver próximo de uma rede de alta qualidade guardada."</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Não reativar"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ativado automaticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Está perto de uma rede guardada: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>."</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Iniciar sessão na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Início de sessão na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ligado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conetividade limitada."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para ligar mesmo assim."</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Alterações às definições de zona Wi-Fi"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"A banda da sua zona Wi-Fi foi alterada."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não suporta a sua preferência apenas para 5 GHz. Em alternativa, este dispositivo vai utilizar a banda de 5 GHz quando estiver disponível."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Mudou para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo utiliza <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Podem aplicar-se custos."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Mudou de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma ligação à internet fraca."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir ligação?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"A aplicação %1$s pretende estabelecer ligação à rede Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uma aplicação"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toque para aceder às definições"</string>
     <string name="accept" msgid="1645267259272829559">"Aceitar"</string>
     <string name="decline" msgid="2112225451706137894">"Recusar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Convite para se ligar"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"O tablet sera temporariamente desligado da rede Wi-Fi enquanto estiver ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"O seu dispositivo Android TV irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O telemóvel irá desligar-se temporariamente da rede Wi-Fi enquanto está ligado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; está a enviar um grande número de mensagens SMS. Pretende autorizar que a aplicação continue a enviar mensagens?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A Poupança de bateria desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades de elevada utilização de energia para prolongar a autonomia da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A Poupança de bateria desativa ou restringe a atividade em segundo plano, alguns efeitos visuais e outras funcionalidades de elevada utilização de energia para prolongar a autonomia da bateria."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 7442703..45a2abd2 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sons do alarme"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sons de notificação"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Desconhecido"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Redes Wi-Fi disponíveis</item>
-      <item quantity="other">Redes Wi-Fi disponíveis</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Abrir redes Wi-Fi disponíveis</item>
-      <item quantity="other">Abrir redes Wi-Fi disponíveis</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conectar a uma rede Wi‑Fi aberta"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Conectando-se à rede Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Conectado a uma rede Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Não foi possível conectar-se à rede Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Toque para ver todas as redes"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectar"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Todas as redes"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Permitir redes Wi-Fi sugeridas?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Redes sugeridas pelo app <xliff:g id="NAME">%s</xliff:g>. O dispositivo pode se conectar automaticamente."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permitir"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Não"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"O Wi‑Fi será ativado automaticamente"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Quando você estiver perto de uma rede salva de alta qualidade"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Não ativar novamente"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ativado automaticamente"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Você está perto de uma rede salva: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Fazer login na rede Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Fazer login na rede"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectado"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> tem conectividade limitada"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Toque para conectar mesmo assim"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mudanças nas suas configurações de ponto de acesso"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Sua banda de ponto de acesso foi alterada."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Este dispositivo não é compatível com sua preferência apenas por 5 GHz. Em vez disso, o dispositivo usará a banda de 5 GHz quando ela estiver disponível."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Alternado para <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"O dispositivo usa <xliff:g id="NEW_NETWORK">%1$s</xliff:g> quando <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> não tem acesso à Internet. Esse serviço pode ser cobrado."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Alternado de <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> para <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"um tipo de rede desconhecido"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" tem uma conexão de baixa qualidade com a Internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permitir conexão?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"O app %1$s deseja se conectar à rede Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Um app"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Toque para ver as configurações"</string>
     <string name="accept" msgid="1645267259272829559">"Aceitar"</string>
     <string name="decline" msgid="2112225451706137894">"Recusar"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Convite para se conectar"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"O tablet desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"O dispositivo Android TV desconectará o Wi-Fi temporariamente enquanto estiver conectado ao <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"O telefone desconectará temporariamente da rede Wi-Fi enquanto estiver conectado a <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; envia uma grande quantidade de mensagens SMS. Quer permitir que este app continue enviando mensagens?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria. "<annotation id="url">"Saiba mais"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"A Economia de bateria desativa ou restringe atividades em segundo plano, alguns efeitos visuais e outros recursos que consomem muita energia, a fim de prolongar a duração da bateria."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 82ec2b6..a878628 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1264,32 +1264,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sunete de alarmă"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sunete pentru notificare"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Necunoscut"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="few">Rețele Wi-Fi disponibile</item>
-      <item quantity="other">Rețele Wi-Fi disponibile</item>
-      <item quantity="one">Rețea Wi-Fi disponibilă</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="few">Rețele Wi-Fi deschise disponibile</item>
-      <item quantity="other">Rețele Wi-Fi deschise disponibile</item>
-      <item quantity="one">Rețea Wi-Fi deschisă disponibilă</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Conectați-vă la o rețea Wi‑Fi deschisă"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Se conectează la rețeaua Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"S-a realizat conexiunea la rețeaua Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nu s-a putut stabili conexiunea la rețeaua Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Atingeți pentru a vedea toate rețelele"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Conectați-vă"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Toate rețelele"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Permiteți rețelele Wi-Fi sugerate?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> a sugerat rețele. Dispozitivul se poate conecta automat."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Permiteți"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nu, mulțumesc"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi se va activa automat"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Când vă aflați lângă o rețea salvată, de înaltă calitate"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Nu reactivați"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi s-a activat automat"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Vă aflați lângă o rețea salvată: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Conectați-vă la rețeaua Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Conectați-vă la rețea"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1302,9 +1276,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Conectat"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> are conectivitate limitată"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Atingeți pentru a vă conecta oricum"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Modificări aduse setărilor pentru hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"S-a schimbat banda de frecvență a hotspotului."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Dispozitivul nu acceptă doar preferința pentru 5 GHz. Dispozitivul va folosi banda de 5 GHz când este disponibilă."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"S-a comutat la <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Dispozitivul folosește <xliff:g id="NEW_NETWORK">%1$s</xliff:g> când <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nu are acces la internet. Se pot aplica taxe."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"S-a comutat de la <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> la <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,27 +1287,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"un tip de rețea necunoscut"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" are o conexiune la internet slabă."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Permiteți conectarea?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplicația %1$s dorește să se conecteze la rețeaua Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"O aplicație"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniți Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Atingeți pentru setări"</string>
     <string name="accept" msgid="1645267259272829559">"Acceptați"</string>
     <string name="decline" msgid="2112225451706137894">"Refuzați"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitația a fost trimisă."</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Invitație pentru conectare"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"De la:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceți codul PIN necesar:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableta se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectată la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Dispozitivul Android TV se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefonul se va deconecta temporar de la rețeaua Wi-Fi cât timp este conectat la <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Introduceți caracterul"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
@@ -1842,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Economisirea bateriei dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții care implică un consum ridicat de energie pentru a prelungi autonomia bateriei. "<annotation id="url">"Aflați mai multe"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Economisirea bateriei dezactivează sau restricționează activitatea în fundal, unele efecte vizuale și alte funcții care implică un consum ridicat de energie pentru a prelungi autonomia bateriei."</string>
+    <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>
@@ -2087,4 +2039,23 @@
     </plurals>
     <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 f01de36..aa94aa6 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Сигнал будильника"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Мелодии уведомлений"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Неизвестно"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Есть доступные сети Wi-Fi</item>
-      <item quantity="few">Есть доступные сети Wi-Fi</item>
-      <item quantity="many">Есть доступные сети Wi-Fi</item>
-      <item quantity="other">Есть доступные сети Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Есть открытые сети Wi-Fi</item>
-      <item quantity="few">Есть открытые сети Wi-Fi</item>
-      <item quantity="many">Есть открытые сети Wi-Fi</item>
-      <item quantity="other">Есть открытые сети Wi-Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Подключитесь к открытой сети Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Идет подключение к сети Wi-Fi…"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Подключено к сети Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не удалось подключиться к сети Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Нажмите, чтобы увидеть список сетей"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Подключиться"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Все сети"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Подключаться к предложенным сетям Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Приложение \"<xliff:g id="NAME">%s</xliff:g>\" рекомендует сети, к которым устройство может подключаться автоматически."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Разрешить"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Нет, спасибо"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi включится автоматически"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Когда вы будете в зоне действия сохраненной сети с хорошим сигналом."</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не включать снова"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi включен автоматически"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Вы находитесь в зоне действия сохраненной сети <xliff:g id="NETWORK_SSID">%1$s</xliff:g>."</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Подключение к Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Регистрация в сети"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Подключено"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Подключение к сети \"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>\" ограничено"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Нажмите, чтобы подключиться"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Изменения в настройках точки доступа"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Частота точки доступа изменена."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Устройство не может работать только на частоте 5 ГГц. Эта частота будет использоваться, когда это возможно."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Новое подключение: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Устройство использует <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, если подключение к сети <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> недоступно. Может взиматься плата за передачу данных."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Устройство отключено от сети <xliff:g id="NEW_NETWORK">%2$s</xliff:g> и теперь использует <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"неизвестный тип сети"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" – плохое интернет-соединение."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Разрешить подключение?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Приложение \"%1$s\" запрашивает доступ на подключение к сети Wi-Fi (%2$s)"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Приложение"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не удалось запустить Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Нажмите, чтобы открыть настройки."</string>
     <string name="accept" msgid="1645267259272829559">"Принять"</string>
     <string name="decline" msgid="2112225451706137894">"Отклонить"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Приглашение отправлено"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Приглашение к подключению"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"От:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетный ПК будет временно отключаться от сети Wi-Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> устройство Android TV будет временно отключаться от сети Wi-Fi."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"При подключении к устройству <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон будет временно отключаться от сети Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Введите символ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; отправляет большое количество SMS. Разрешить приложению и дальше отправлять сообщения?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"В режиме энергосбережения ограничиваются или приостанавливаются фоновые процессы, визуальные эффекты и другие функции, которые быстро расходуют заряд батареи. "<annotation id="url">"Подробнее…"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"В режиме энергосбережения ограничиваются или приостанавливаются фоновые процессы, визуальные эффекты и другие функции, которые быстро расходуют заряд батареи."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 6dbf502..ee261a54 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1246,30 +1246,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"එලාම හඬ"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"දැනුම්දීම් හඬ"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"නොදනී"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Wi-Fi ජාල තිබේ</item>
-      <item quantity="other">Wi-Fi ජාල තිබේ</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">විවෘත Wi-Fi ජාල තිබේ</item>
-      <item quantity="other">විවෘත Wi-Fi ජාල තිබේ</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"විවෘත Wi-Fi ජාලය වෙත සම්බන්ධ වෙන්න"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi-Fi ජාලයට සම්බන්ධ වෙමින්"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi-Fi ජාලයක් වෙත සම්බන්ධ විය"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi-Fi ජාලයක් වෙත සම්බන්ධ විය නොහැකි විය"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"සියලු ජාල බැලීමට තට්ටු කරන්න"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"සම්බන්ධ කරන්න"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"සියලු ජාල"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"යෝජිත Wi-Fi ජාල ඉඩ දෙන්නද?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> යෝජිත ජාල. උපාංගය ස්වයංක්‍රියව සම්බන්ධ වනු ඇත."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"ඉඩ දෙන්න"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"එපා, ස්තූතියි"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi ස්වයංක්‍රියව ක්‍රියාත්මක වනු ඇත"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"ඔබ උසස් තත්ත්වයේ සුරැකි ජාලයක් අවට සිටින විට"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"නැවත ක්‍රියාත්මක නොකරන්න"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi ස්වයංක්‍රියව ක්‍රියාත්මක කරන ලදි"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"ඔබ සුරැකි ජාලයක් අවට සිටී: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi ජාලයට පුරනය වන්න"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ජාලයට පුරනය වන්න"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1282,9 +1258,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"සම්බන්ධයි"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> හට සීමිත සබැඳුම් හැකියාවක් ඇත"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"කෙසේ වෙතත් ඉදිරියට යාමට තට්ටු කරන්න"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"ඔබගේ හොට්ස්පොට් සැකසීම්වලට වෙනස් කිරීම්"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ඔබගේ හොට්ස්පොට් කලාපය වෙනස් වී ඇත."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"මෙම උපාංගය 5GHz සඳහා ඔබේ මනාපවලට සහාය නොදක්වයි. ඒ වෙනුවට, මෙම උපාංගය ලබා ගත හැකි විට 5GHz කලාපය භාවිතා කරනු ඇත."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> වෙත මාරු විය"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"උපාංගය <xliff:g id="NEW_NETWORK">%1$s</xliff:g> <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> සඳහා අන්තර්ජාල ප්‍රවේශය නැති විට භාවිත කරයි. ගාස්තු අදාළ විය හැකිය."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> සිට <xliff:g id="NEW_NETWORK">%2$s</xliff:g> වෙත මාරු විය"</string>
@@ -1296,27 +1269,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"නොදන්නා ජාල වර්ගයකි"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi වෙත සම්බන්ධ විය නොහැක"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" වෙත දුර්වල අන්තර්ජාල සම්බන්ධතාවයක් ඇත."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"සම්බන්ධතාවයට ඉඩ දෙන්නද?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"යෙදුම් %1$s ක් WiFi ජාලය %2$s වෙත සම්බන්ධ කිරීමට කැමතියි"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"යෙදුම"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct ආරම්භ කරන්න. මෙය Wi-Fi සේවාදායක/හොට්ස්පොට් එක අක්‍රිය කරනු ඇත."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ආරම්භ කළ නොහැක."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ක්‍රියාත්මකයි"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"සැකසීම් සඳහා තට්ටු කරන්න"</string>
     <string name="accept" msgid="1645267259272829559">"පිළිගන්න"</string>
     <string name="decline" msgid="2112225451706137894">"ප්‍රතික්ෂේප කරන්න"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ආරාධනාව යවන ලදි"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"සම්බන්ධතාවයට ඇරයුමකි"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"වෙතින්:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"වෙත:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"අවශ්‍ය PIN එක ටයිප් කරන්න:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"ටැබ්ලටය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වන අතරතුර එය Wi-Fi වලින් තාවකාලිකව විසන්ධි කෙරේ."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"ඔබගේ Android TV උපාංගය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වී පවතින විට Wi-Fi වෙතින් එය තාවකාලිකව විසන්ධි වනු ඇත"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"දුරකථනය <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ට සම්බන්ධ වී පවතින විට Wi-Fi වලින් එය තාවකාලිකව විසන්ධි වෙයි."</string>
     <string name="select_character" msgid="3365550120617701745">"අකුර ඇතුළත් කරන්න"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS පණිවිඩ යවමින්"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; SMS පණිවිඩ විශාල ගණනක් යවයි. මෙම යෙදුමට පණිවිඩ යැවීම නොනැවතී කරගෙන යාමට අවසර දීමට ඔබට අවශ්‍යද?"</string>
@@ -1819,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"බැටරි සුරැකුම අක්‍රිය වෙයි, නැති නම් බැටරි ආයු කාලය දීර්ඝ කිරීමට පසුබිම් ක්‍රියාකාරකම, සමහර දෘශ්‍යමාන බලපෑම් සහ අනෙකුත් ඉහළ බල විශේෂාංග සීමා කරයි. "<annotation id="url">"තවත් දැන ගන්න"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"බැටරි සුරැකුම අක්‍රිය වෙයි, නැති නම් බැටරි ආයු කාලය දීර්ඝ කිරීමට පසුබිම් ක්‍රියාකාරකම, සමහර දෘශ්‍යමාන බලපෑම් සහ අනෙකුත් ඉහළ බල විශේෂාංග සීමා කරයි."</string>
+    <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>
@@ -2053,4 +2007,23 @@
     </plurals>
     <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 18a8794..ed4f68c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvuky budíka"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvuky upozornení"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Neznáme"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="few">K dispozícii sú siete Wi‑Fi</item>
-      <item quantity="many">K dispozícii sú siete Wi‑Fi</item>
-      <item quantity="other">K dispozícii sú siete Wi‑Fi</item>
-      <item quantity="one">K dispozícii je sieť Wi‑Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="few">K dispozícii sú verejné siete Wi‑Fi</item>
-      <item quantity="many">K dispozícii sú verejné siete Wi‑Fi</item>
-      <item quantity="other">K dispozícii sú verejné siete Wi‑Fi</item>
-      <item quantity="one">K dispozícii je verejná sieť Wi‑Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Pripojenie k otvorenej sieti Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Pripája sa k sieti Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Pripojenie k sieti Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"K sieti Wi‑Fi sa nepodarilo pripojiť"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Klepnutím zobrazíte všetky siete"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Pripojiť"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Všetky siete"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Chcete povoliť navrhované siete Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Siete navrhuje aplikácia <xliff:g id="NAME">%s</xliff:g>. Zariadenie sa môže pripájať automaticky."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Povoliť"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nie, ďakujem"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi sa zapne automaticky"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Keď budete v blízkosti kvalitnej uloženej siete"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Znova nezapínať"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Pripojenie Wi‑Fi sa zaplo automaticky"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ste v blízkosti uloženej siete: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prihlásiť sa do siete Wi‑Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prihlásenie do siete"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Pripojené"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> má obmedzené pripojenie"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Ak sa chcete aj napriek tomu pripojiť, klepnite"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Zmeny nastavení hotspotu"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pásmo vášho hotspotu sa zmenilo."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Toto zariadenie nepodporuje vašu predvoľbu používať iba 5 GHz. Namiesto toho bude pásmo 5 GHz používať vtedy, keď bude k dispozícii."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Prepnuté na sieť: <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Keď <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nemá prístup k internetu, zariadenie používa <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Môžu sa účtovať poplatky."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Prepnuté zo siete <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sieť <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznámy typ siete"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi‑Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" má nekvalitné internetové pripojenie."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Povoliť pripojenie?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikácia %1$s sa chce pripojiť k sieti Wi‑Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikácia"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi‑Fi"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi‑Fi. Táto možnosť vypne sieť Wi‑Fi v režime klient alebo hotspot."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Priame pripojenie siete Wi‑Fi sa nepodarilo spustiť"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi‑Fi je zapnuté"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Klepnutím zobrazíte nastavenia"</string>
     <string name="accept" msgid="1645267259272829559">"Prijať"</string>
     <string name="decline" msgid="2112225451706137894">"Odmietnuť"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka bola odoslaná"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Pozvánka na pripojenie"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi‑Fi dočasne odpojený."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Zariadenie Android TV sa počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dočasne odpojí od siete Wi‑Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefón bude počas pripojenia k zariadeniu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> od siete Wi‑Fi dočasne odpojený."</string>
     <string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Aplikácia &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; posiela veľký počet správ SMS. Chcete tejto aplikácií povoliť, aby aj naďalej posielala správy?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Šetrič batérie vypne alebo obmedzí aktivitu na pozadí, niektoré vizuálne efekty a ďalšie energeticky náročné funkcie, aby predĺžil výdrž batérie. "<annotation id="url">"Ďalšie informácie"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Šetrič batérie vypne alebo obmedzí aktivitu na pozadí, niektoré vizuálne efekty a ďalšie energeticky náročné funkcie, aby predĺžil výdrž batérie."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 40d0dde..dc162a8 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Zvoki alarma"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Zvoki obvestil"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Neznano"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Na voljo so omrežja Wi-Fi</item>
-      <item quantity="two">Na voljo so omrežja Wi-Fi</item>
-      <item quantity="few">Na voljo so omrežja Wi-Fi</item>
-      <item quantity="other">Na voljo so omrežja Wi-Fi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Na voljo so odprta omrežja Wi-Fi</item>
-      <item quantity="two">Na voljo so odprta omrežja Wi-Fi</item>
-      <item quantity="few">Na voljo so odprta omrežja Wi-Fi</item>
-      <item quantity="other">Na voljo so odprta omrežja Wi-Fi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Vzpostavite povezavo z odprtim omrežjem Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Vzpostavljanje povezave z omrežjem Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Povezava z omrežjem Wi-Fi je vzpostavljena"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Povezave z omrežjem Wi-Fi ni bilo mogoče vzpostaviti"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Dotaknite se, če si želite ogledati vsa omrežja"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Vzpostavi povezavo"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Vsa omrežja"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Želite dovoliti predlagana omrežja Wi-Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> – predlagana omrežja. Naprava se lahko poveže samodejno."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Dovoli"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ne, hvala"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Povezava Wi‑Fi se bo samodejno vklopila"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Ko ste v bližini zanesljivega shranjenega omrežja"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ne vklopi znova"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi je bil vklopljen samodejno"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ste v bližini shranjenega omrežja: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Prijavite se v omrežje Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Prijava v omrežje"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Povezava je vzpostavljena"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Povezljivost omrežja <xliff:g id="NETWORK_SSID">%1$s</xliff:g> je omejena"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Dotaknite se, da kljub temu vzpostavite povezavo"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Spremembe nastavitev dostopne točke"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Pas dostopne točke je spremenjen."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Ta naprava ne podpira prednostne nastavitve samo za 5-GHz pas. Namesto tega bo ta naprava uporabljala 5-GHz pas, ko bo na voljo."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Preklopljeno na omrežje vrste <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Naprava uporabi omrežje vrste <xliff:g id="NEW_NETWORK">%1$s</xliff:g>, ko omrežje vrste <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nima dostopa do interneta. Prenos podatkov se lahko zaračuna."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Preklopljeno z omrežja vrste <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na omrežje vrste <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"neznana vrsta omrežja"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ima slabo internetno povezavo."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ali dovolite vzpostavitev povezave?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacija %1$s želi vzpostaviti povezavo z omrežjem Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Aplikacija"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dotaknite se za nastavitve"</string>
     <string name="accept" msgid="1645267259272829559">"Sprejmem"</string>
     <string name="decline" msgid="2112225451706137894">"Zavrni"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Povabilo za povezavo"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Od:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Za:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablični računalnik bo začasno prekinil povezavo z Wi-Fi-jem, medtem ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Naprava Android TV bo začasno prekinila povezavo z omrežjem Wi-Fi, medtem ko je povezana z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon bo začasno prekinil povezavo z Wi-Fi-jem, ko je povezan z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; pošilja veliko SMS-ov. Ali želite dovoliti, da jih še naprej pošilja?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Varčevanje z energijo akumulatorja izklopi ali omeji dejavnost v ozadju, nekatere vizualne učinke in druge funkcije z visoko porabo energije, da podaljša čas delovanja akumulatorja. "<annotation id="url">"Več o tem"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Varčevanje z energijo akumulatorja izklopi ali omeji dejavnost v ozadju, nekatere vizualne učinke in druge funkcije z visoko porabo energije, da podaljša čas delovanja akumulatorja."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 ee46d3b..4973f9f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Tingujt e alarmeve"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Tingujt e njoftimeve"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"E panjohur"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Rrjete Wi-Fi ofrohen për përdorim</item>
-      <item quantity="one">Një rrjet Wi-Fi ofrohet për përdorim</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Rrjete të hapura Wi-Fi në përdorim</item>
-      <item quantity="one">Rrjet i hapur Wi-Fi në përdorim</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Lidhu me rrjetin e hapur Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Po lidhet me rrjetin Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Lidhur me rrjetin e hapur Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Nuk mund të lidhet me rrjetin Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Trokit për të parë të gjitha rrjetet"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Lidhu"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Të gjitha rrjetet"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Të lejohen rrjetet e sugjeruara Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Rrjet e sugjeruara të <xliff:g id="NAME">%s</xliff:g>. Pajisja mund të lidhet automatikisht."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Lejo"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Jo, faleminderit"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi do të aktivizohet automatikisht"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kur ndodhesh pranë një rrjeti të ruajtur me cilësi të lartë"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Mos e aktivizo përsëri"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi u aktivizua automatikisht"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ndodhesh pranë një rrjeti të ruajtur: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Identifikohu në rrjetin Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Identifikohu në rrjet"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Lidhur"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ka lidhshmëri të kufizuar"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Trokit për t\'u lidhur gjithsesi"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ndryshimet në cilësimet e zonës së qasjes për internet"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Brezi yt i zonës së qasjes për internet ka ndryshuar."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Kjo pajisje nuk e mbështet preferencën për vetëm 5 GHz. Përkundrazi, pajisja do të përdorë brezin 5 GHz nëse ka."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Kaloi te <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Pajisja përdor <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kur <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> nuk ka qasje në internet. Mund të zbatohen tarifa."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kaloi nga <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> te <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"një lloj rrjeti i panjohur"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nuk mund të lidhej me Wi-Fi"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Të lejohet lidhja?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Aplikacioni %1$s do të lidhet me rrjetin Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Një aplikacion"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direkt"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Fillo \"Wi-Fi Direkt\". Kjo do ta çaktivizojë klientin ose zonën e qasjes Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nuk mundi të fillonte \"Wi-Fi Direkt\"."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"\"Wi-Fi Direkt\" është aktiv"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Trokit për cilësimet"</string>
     <string name="accept" msgid="1645267259272829559">"Prano"</string>
     <string name="decline" msgid="2112225451706137894">"Refuzo"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Ftesa u dërgua"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Ftesë për t\'u lidhur"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Nga:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Për:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Shkruaj PIN-in e kërkuar:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-i:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tableti do të shkëputet përkohësisht nga Wi-Fi gjatë kohës së lidhjes me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Pajisja jote Android TV do të shkëputet përkohësisht nga Wi-Fi ndërkohë që është e lidhur me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefoni do të shkëputet përkohësisht nga Wi-Fi gjatë kohës së lidhjes me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Fut karakterin"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Po dërgon mesazhe SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; po dërgon një numër të lartë mesazhesh SMS. Do ta lejosh aplikacionin të vazhdojë të dërgojë mesazhe?"</string>
@@ -1818,8 +1771,10 @@
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Përditësuar nga administratori"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Fshirë nga administratori"</string>
     <string name="confirm_battery_saver" msgid="639106420541753635">"Në rregull"</string>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"\"Kursyesi i baterisë\" çaktivizohet ose kufizon aktivitetin në sfond, disa efekte vizuale dhe funksione të tjera me nivel të lartë energjie për të rritur kohëzgjatjen e baterisë. "<annotation id="url">"Mëso më shumë"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"\"Kursyesi i baterisë\" çaktivizohet ose kufizon aktivitetin në sfond, disa efekte vizuale dhe funksione të tjera me nivel të lartë energjie për të rritur kohëzgjatjen e baterisë."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <string name="data_saver_description" msgid="6015391409098303235">"Për të ndihmuar në reduktimin e përdorimit të të dhënave, \"Kursyesi i të dhënave\" pengon që disa aplikacione të dërgojnë apo të marrin të dhëna në sfond. Një aplikacion që po përdor aktualisht mund të ketë qasje te të dhënat, por këtë mund ta bëjë më rrallë. Kjo mund të nënkuptojë, për shembull, se imazhet nuk shfaqen kur troket mbi to."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Të aktivizohet \"Kursyesi i të dhënave\"?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktivizo"</string>
@@ -2052,4 +2007,23 @@
     </plurals>
     <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 7fd7353..48658bb 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -48,7 +48,7 @@
     <string name="invalidPin" msgid="3850018445187475377">"Откуцајте PIN који има од 4 до 8 бројева."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"Унесите PUK који се састоји од 8 цифара или више."</string>
     <string name="needPuk" msgid="919668385956251611">"SIM картица је закључана PUK кодом. Унесите PUK кôд да бисте је откључали."</string>
-    <string name="needPuk2" msgid="4526033371987193070">"Унесите PUK2 да бисте деблокирали SIM картицу."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"Унесите PUK2 да бисте одблокирали SIM картицу."</string>
     <string name="enablePin" msgid="209412020907207950">"Није успело. Омогућите закључавање SIM/RUIM картице."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
       <item quantity="one">Имате још <xliff:g id="NUMBER_1">%d</xliff:g> покушај пре него што се SIM картица закључа.</item>
@@ -1264,32 +1264,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Звуци аларма"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Звуци обавештења"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Непознато"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Wi-Fi мреже су доступне</item>
-      <item quantity="few">Wi-Fi мреже су доступне</item>
-      <item quantity="other">Wi-Fi мреже су доступне</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Отворене Wi-Fi мреже су доступне</item>
-      <item quantity="few">Отворене Wi-Fi мреже су доступне</item>
-      <item quantity="other">Отворене Wi-Fi мреже су доступне</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Повежите се са отвореном Wi‑Fi мрежом"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Повезује се са Wi-Fi мрежом..."</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Повезали сте се са Wi‑Fi мрежом"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Повезивање са Wi‑Fi мрежом није успело"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Додирните да бисте видели све мреже"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Повежи"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Све мреже"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Желите да дозволите предложене Wi‑Fi мреже?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Мреже које предлаже <xliff:g id="NAME">%s</xliff:g>. Уређај ће се можда повезати аутоматски."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Дозволи"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Не, хвала"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi ће се аутоматски укључити"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Када сте у близини сачуване мреже високог квалитета"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не укључуј поново"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi је аутоматски укључен"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"У близини сте сачуване мреже: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Пријављивање на Wi-Fi мрежу"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Пријавите се на мрежу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1302,9 +1276,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Повезано је"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> има ограничену везу"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Додирните да бисте се ипак повезали"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Промене подешавања за хотспот"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Опсег хотспота је промењен."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Овај уређај не подржава подешавање само за 5 GHz. Уређај ће користити опсег од 5 GHz када буде доступан."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Прешли сте на тип мреже <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Уређај користи тип мреже <xliff:g id="NEW_NETWORK">%1$s</xliff:g> када тип мреже <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> нема приступ интернету. Можда ће се наплаћивати трошкови."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Прешли сте са типа мреже <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на тип мреже <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1316,27 +1287,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"непознат тип мреже"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није могуће повезати са Wi-Fi мрежом"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" има лошу интернет везу."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Желите ли да дозволите повезивање?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Апликација %1$s жели да се повеже на Wi-Fi мрежу %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Апликација"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Није могуће покренути Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Додирните за подешавања"</string>
     <string name="accept" msgid="1645267259272829559">"Прихвати"</string>
     <string name="decline" msgid="2112225451706137894">"Одбиј"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Позивница је послата"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Позивница за повезивање"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Од:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Коме:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Таблет ће привремено прекинути везу са Wi-Fi-јем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV уређај ће привремено прекинути везу са Wi-Fi мрежом док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Телефон ће привремено прекинути везу са Wi-Fi-јем док је повезан са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Уметање знака"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; шаље велики број SMS порука. Желите ли да дозволите овој апликацији да настави са слањем порука?"</string>
@@ -1842,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Уштеда батерије искључује или ограничава активност у позадини, неке визуелне ефекте и друге функције са високом потрошњом да би продужила трајање батерије. "<annotation id="url">"Сазнајте више"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Уштеда батерије искључује или ограничава активност у позадини, неке визуелне ефекте и друге функције са високом потрошњом да би продужила трајање батерије."</string>
+    <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>
@@ -2087,4 +2039,23 @@
     </plurals>
     <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 b8da1b6..09a2513 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Ljud för alarm"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Aviseringsljud"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Okänt"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi-nätverk är tillgängliga</item>
-      <item quantity="one">Wi-Fi-nätverk är tillgängligt</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Öppna Wi-Fi-nätverk är tillgängliga</item>
-      <item quantity="one">Öppet Wi-Fi-nätverk är tillgängligt</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Anslut till ett öppet Wi-Fi-nätverk"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Ansluter till Wi-Fi-nätverk"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Ansluten till Wi-Fi-nätverket"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Det gick inte att ansluta till Wi‑Fi-nätverket"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tryck för att visa alla nätverk"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Anslut"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Alla nätverk"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vill du tillåta föreslagna Wi-Fi-nätverk?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Nätverk som föreslagits av <xliff:g id="NAME">%s</xliff:g>. Enheten kan anslutas automatiskt."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Tillåt"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Nej tack"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi aktiveras automatiskt"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"När du är i närheten av ett sparat nätverk av hög kvalitet"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Återaktivera inte"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi aktiverades automatiskt"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Du är i närheten av ett sparat nätverk: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Logga in på ett Wi-Fi-nätverk"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Logga in på nätverket"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ansluten"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> har begränsad anslutning"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Tryck för att ansluta ändå"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ändringar i inställningarna för surfzon"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Frekvensbandet för surfzonen har ändrats."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Den här enheten har inte stöd för inställningen för att endast använda 5 GHz. I stället används 5 GHz när det är möjligt."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Byte av nätverk till <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="NEW_NETWORK">%1$s</xliff:g> används på enheten när det inte finns internetåtkomst via <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Avgifter kan tillkomma."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Byte av nätverk från <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> till <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"en okänd nätverkstyp"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" har en dålig Internetanslutning."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Tillåt anslutning?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Appen %1$s vill ansluta till Wi-Fi-nätverket %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"En app"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/surfzon."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Det gick inte att starta Wi-Fi direkt."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Tryck för inställningar"</string>
     <string name="accept" msgid="1645267259272829559">"Godkänn"</string>
     <string name="decline" msgid="2112225451706137894">"Avvisa"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Inbjudan har skickats"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Inbjudan om att ansluta"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Från:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Till:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Surfplattans Wi-Fi-anslutning kommer tillfälligt att avbrytas när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV-enheten kopplas tillfälligt från Wi-Fi medan den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Mobilen kommer tillfälligt att kopplas från Wi-Fi när den är ansluten till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; skickar ett stort antal SMS. Vill du tillåta att appen fortsätter att skicka meddelanden?"</string>
@@ -1460,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>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"I batterisparläget inaktiveras eller begränsas aktivitet i bakgrunden, vissa visuella effekter och andra funktioner som drar mycket ström i syfte att förlänga batteritiden. "<annotation id="url">"Läs mer"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"I batterisparläget inaktiveras eller begränsas aktivitet i bakgrunden, vissa visuella effekter och andra funktioner som drar mycket ström i syfte att förlänga batteritiden."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 88221b6..483c39f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Sauti za kengele"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Sauti za arifa"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Haijulikani"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Mitandao ya Wi-Fi inapatikana</item>
-      <item quantity="one">Mtandao wa Wi-Fi unapatikana</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Fungua mitandao ya Wi-Fi inayopatikana</item>
-      <item quantity="one">Fungua mtandao wa Wi-Fi unaopatikana</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Unganisha kwenye mtandao wa Wi‑Fi unaotumiwa na mtu yeyote"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Inaunganisha kwenye mtandao wa Wi‑Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Imeunganisha kwenye mtandao wa Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Imeshindwa kuunganisha kwenye mtandao wa Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Gusa ili uone mitandao yote"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Unganisha"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Mitandao yote"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Ungependa kuruhusu mitandao inayopendekezwa ya Wi-Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Mitandao inayopendekezwa kwa ajili ya <xliff:g id="NAME">%s</xliff:g>. Huenda kifaa kikaunganisha kiotomatiki."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Ruhusu"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Hapana, asante"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi itawashwa kiotomatiki"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Unapokuwa karibu na mtandao uliohifadhiwa wenye ubora wa juu"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Usiwashe tena"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi imewashwa kiotomatiki"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Uko karibu na mtandao uliohifadhiwa: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ingia kwa mtandao wa Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ingia katika mtandao"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Imeunganisha"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> ina muunganisho unaofikia huduma chache."</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Gusa ili uunganishe tu"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mabadiliko kwenye mipangilio ya mtandao pepe"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Bendi ya mtandao pepe wako imebadilika."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Kifaa hiki hakitumii mapendeleo yako ya GHz 5 pekee. Badala yake, kifaa hiki kitatumia bendi ya GHz 5 itakapopatikana."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Sasa inatumia <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Kifaa hutumia <xliff:g id="NEW_NETWORK">%1$s</xliff:g> wakati <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> haina intaneti. Huenda ukalipishwa."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Imebadilisha mtandao kutoka <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> na sasa inatumia <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"aina ya mtandao isiyojulikana"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Imeshindwa kuunganisha Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inao muunganisho duni wa wavuti."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ungepenga kuruhusu muunganisho?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Programu ya %1$s ingependa kuunganisha kwenye Mtandao wa Wifi wa %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Programu"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Moja kwa Moja"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima kiteja cha Wi-Fi/mtandaopepe."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Haikuweza kuanzisha Wi-Fi Moja kwa Moja."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Moja kwa Moja imewashwa"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Gusa ili uweke mipangilio"</string>
     <string name="accept" msgid="1645267259272829559">"Kubali"</string>
     <string name="decline" msgid="2112225451706137894">"Kataa"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Mwaliko umetumwa"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Mwaliko wa kuunganisha"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kutoka:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kwa:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Kompyuta ndogo itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Kifaa chako cha Android TV kitatenganishwa na Wi-Fi kwa muda wakati kimeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Simu itaukata muunganisho kwa muda kutoka kwenye Wi-Fi inapokuwa imeunganishwa kwenye <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; inatuma idadi kubwa ya SMS. Je, unataka kuruhusu programu hii kuendelea kutuma SMS?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Kiokoa betri huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vinavyotumia nishati nyingi ili kuongeza muda wa matumizi ya betri. "<annotation id="url">"Pata maelezo zaidi"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Kiokoa betri huzima au kuzuia shughuli za chinichini, baadhi ya madoido yanayoonekana na vipengele vinavyotumia nishati nyingi ili kuongeza muda wa matumizi ya betri."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 6c35423..0c4e20e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -630,7 +630,7 @@
     <string name="permlab_modifyNetworkAccounting" msgid="5088217309088729650">"பிணைய பயன்பாட்டு கணக்கிடுதலை மாற்றுதல்"</string>
     <string name="permdesc_modifyNetworkAccounting" msgid="5443412866746198123">"ஆப்ஸ்களுக்கு எதிராக நெட்வொர்க் ஆப்ஸ் எவ்வாறு கணக்கிடப்படுகிறது என்பதை மாற்ற ஆப்ஸை அனுமதிக்கிறது. இயல்பான ஆப்ஸ்களால் பயன்படுத்தப்படுவதற்காக அல்ல."</string>
     <string name="permlab_accessNotifications" msgid="7673416487873432268">"அறிவிப்புகளின் அணுகல்"</string>
-    <string name="permdesc_accessNotifications" msgid="458457742683431387">"பிற பயன்பாடுகளால் இடுகையிடப்பட்ட அறிவிப்புகள் உள்பட எல்லா அறிவிப்புகளையும் பெற, பார்க்க மற்றும் அழிக்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
+    <string name="permdesc_accessNotifications" msgid="458457742683431387">"பிற ஆப்ஸால் இடுகையிடப்பட்ட அறிவிப்புகள் உள்பட எல்லா அறிவிப்புகளையும் பெற, பார்க்க மற்றும் அழிக்கப் ஆப்ஸை அனுமதிக்கிறது."</string>
     <string name="permlab_bindNotificationListenerService" msgid="7057764742211656654">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையுடன் இணைத்தல்"</string>
     <string name="permdesc_bindNotificationListenerService" msgid="985697918576902986">"அறிவிப்புகளைக் கண்காணிக்கும் சேவையின் உயர் நிலை இடைமுகத்துடன் இணைப்பதற்கு ஹோல்டரை அனுமதிக்கிறது. இயல்பான பயன்பாடுகளுக்கு எப்போதுமே தேவைப்படாது."</string>
     <string name="permlab_bindConditionProviderService" msgid="1180107672332704641">"நிபந்தனை வழங்குநர் சேவையுடன் இணைத்தல்"</string>
@@ -939,7 +939,7 @@
     <string name="autofill_area" msgid="3547409050889952423">"பகுதி"</string>
     <string name="autofill_emirate" msgid="2893880978835698818">"எமிரேட்"</string>
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"உங்கள் இணையப் புத்தக்கக்குறிகள் மற்றும் வரலாற்றைப் படித்தல்"</string>
-    <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"உலாவி மூலம் பார்வையிட்ட எல்லா URLகளின் வரலாற்றையும், உலாவியில் குறிக்கப்பட்ட எல்லா புத்தகக்குறிகளையும் படிக்கப் ஆப்ஸை அனுமதிக்கிறது. குறிப்பு: மூன்றாம் தரப்பு உலாவிகள் அல்லது இணைய உலாவல் திறன்களுடன் கூடிய பிற பயன்பாடுகளால் இந்த அனுமதி செயற்படுத்தப்படாமல் போகலாம்."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"உலாவி மூலம் பார்வையிட்ட எல்லா URLகளின் வரலாற்றையும், உலாவியில் குறிக்கப்பட்ட எல்லா புத்தகக்குறிகளையும் படிக்கப் ஆப்ஸை அனுமதிக்கிறது. குறிப்பு: மூன்றாம் தரப்பு உலாவிகள் அல்லது இணைய உலாவல் திறன்களுடன் கூடிய பிற ஆப்ஸால் இந்த அனுமதி செயற்படுத்தப்படாமல் போகலாம்."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"இணையப் புத்தகக்குறிகளையும், வரலாற்றையும் எழுதுதல்"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"உங்கள் டேப்லெட்டில் சேமிக்கப்பட்ட உலாவியின் வரலாறு அல்லது புத்தகக்குறிகளைத் திருத்த ஆப்ஸை அனுமதிக்கிறது. இது உலாவியின் தரவை அழிக்கவோ, திருத்தவோ ஆப்ஸை அனுமதிக்கலாம். குறிப்பு: இணைய உலாவல் செயல்திறன்கள் மூலம் மூன்றாம் தரப்பு உலாவிகள் அல்லது பிற ஆப்ஸ் இந்த அனுமதியைச் செயற்படுத்த முடியாது."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="6340829212433680418">"Android TVயில் சேமித்துள்ள உலாவியின் மூலம் பார்க்கப்பட்ட தளங்களையோ புக்மார்க்குகளையோ திருத்த ஆப்ஸை அனுமதிக்கும். இது உலாவியின் தரவை அழிக்கவோ திருத்தவோ ஆப்ஸை அனுமதிக்கக்கூடும். கவனத்திற்கு: மூன்றாம் தரப்பு உலாவிகளோ இணைய உலாவல் திறன்களுடன் கூடிய பிற ஆப்ஸோ இந்த அனுமதியைச் செயல்படுத்த முடியாது."</string>
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"அலார ஒலிகள்"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"அறிவிப்பு ஒலிகள்"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"தெரியாதது"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
-      <item quantity="one">வைஃபை நெட்வொர்க் உள்ளது</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">பொது வைஃபை நெட்வொர்க்குகள் உள்ளன</item>
-      <item quantity="one">பொது வைஃபை நெட்வொர்க் உள்ளது</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"திறந்த வைஃபை நெட்வொர்க்குடன் இணைக்கவும்"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"வைஃபை நெட்வொர்க்குடன் இணைக்கிறது"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"வைஃபை நெட்வொர்க்குடன் இணைக்கப்பட்டது"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"வைஃபை நெட்வொர்க்குடன் இணைக்க முடியவில்லை"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"எல்லா நெட்வொர்க்குகளையும் பார்க்க, தட்டவும்"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"இணை"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"எல்லா நெட்வொர்க்குகளும்"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"பரிந்துரைக்கப்பட்ட வைஃபை நெட்வொர்க்குகளை அனுமதிக்க வேண்டுமா?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> பரிந்துரைக்கும் நெட்வொர்க்குகள். சாதனம் தானாக இணைக்கப்படக்கூடும்."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"அனுமதி"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"வேண்டாம்"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"வைஃபை தானாக ஆன் ஆகும்"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"சேமித்த, உயர்தர நெட்வொர்க்கிற்கு அருகில் இருக்கும்போது"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"மீண்டும் ஆன் செய்யாதே"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"வைஃபை தானாகவே ஆன் செய்யப்பட்டது"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> என்ற சேமிக்கப்பட்ட நெட்வொர்க் அருகில் உள்ளீர்கள்"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"வைஃபை நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"நெட்வொர்க்கில் உள்நுழையவும்"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"இணைக்கப்பட்டது"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> வரம்பிற்கு உட்பட்ட இணைப்புநிலையைக் கொண்டுள்ளது"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"எப்படியேனும் இணைப்பதற்குத் தட்டவும்"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"உங்கள் ஹாட்ஸ்பாட் அமைப்புகளில் செய்யப்பட்டுள்ள மாற்றங்கள்"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"உங்கள் ஹாட்ஸ்பாட்டின் அலைவரிசை மாறிவிட்டது."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"இந்தச் சாதனத்தில், ’5GHz மட்டும்’ எனும் முன்னுரிமைத் தேர்வு ஆதரிக்கப்படவில்லை. எனினும் 5GHz அலைவரிசை கிடைக்கும்போது, சாதனம் அதைப் பயன்படுத்திக்கொள்ளும்."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> நெட்வொர்க்கில் இண்டர்நெட் அணுகல் இல்லாததால், சாதனமானது <xliff:g id="NEW_NETWORK">%1$s</xliff:g> நெட்வொர்க்கைப் பயன்படுத்துகிறது. கட்டணங்கள் விதிக்கப்படலாம்."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> இலிருந்து <xliff:g id="NEW_NETWORK">%2$s</xliff:g>க்கு மாற்றப்பட்டது"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"தெரியாத நெட்வொர்க் வகை"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"வைஃபை உடன் இணைக்க முடியவில்லை"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"இணைப்பை அனுமதிக்கவா?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%2$s வைஃபை நெட்வொர்க்குடன், %1$s ஆப்ஸ் இணைக்க விரும்புகிறது"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ஒரு ஆப்ஸ்"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"வைஃபை டைரக்ட்"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"வைஃபை Direct ஐத் தொடங்குக. இது வைஃபை க்ளையண்ட்/ஹாட்ஸ்பாட்டை முடக்கும்."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"வைஃபை Direct ஐத் தொடங்க முடியவில்லை."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"வைஃபை Direct இயக்கத்தில் உள்ளது"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"அமைப்புகளுக்கு, தட்டவும்"</string>
     <string name="accept" msgid="1645267259272829559">"ஏற்கிறேன்"</string>
     <string name="decline" msgid="2112225451706137894">"நிராகரி"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"அழைப்பு அனுப்பப்பட்டது"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"இணைவதற்கான அழைப்பு"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"அனுப்புநர்:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"பெறுநர்:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"பின்வரும் அவசியமான பின்னை உள்ளிடவும்:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"பின்:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் டேப்லெட் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"உங்கள் Android TV <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்துடன் இணைக்கப்பட்டிருக்கும் போது வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் மொபைல் இணைக்கப்படும்போது, வைஃபையிலிருந்து தற்காலிகமாகத் துண்டிக்கப்படும்."</string>
     <string name="select_character" msgid="3365550120617701745">"எழுத்துக்குறியைச் செருகு"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS குறுந்தகவல்களை அனுப்புகிறது"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"அதிக எண்ணிக்கையிலான SMS குறுஞ்செய்திகளை &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; அனுப்புகிறது. செய்திகளை அனுப்புவதைத் தொடர இந்த ஆப்ஸை அனுமதிக்க விரும்புகிறீர்களா?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"பேட்டரி நிலையை நீட்டிப்பதற்காகப் பின்னணிச் செயல்பாடு, விஷுவல் எஃபெக்ட்ஸ் மற்றும் அதிக மின்சக்தியைப் பயன்படுத்தும் அம்சங்களைப் பேட்டரி சேமிப்பான் ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும். "<annotation id="url">"மேலும் அறிக"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"பேட்டரி நிலையை நீட்டிப்பதற்காகப் பின்னணிச் செயல்பாடு, விஷுவல் எஃபெக்ட்ஸ் மற்றும் அதிக மின்சக்தியைப் பயன்படுத்தும் அம்சங்களைப் பேட்டரி சேமிப்பான் ஆஃப் செய்யும் அல்லது கட்டுப்படுத்தும்."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 7e91460..1b3df6e 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -283,9 +283,9 @@
     <string name="permgrouprequest_contacts" msgid="6032805601881764300">"మీ పరిచయాలను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ని అనుమతించాలా?"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"స్థానం"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
-    <string name="permgrouprequest_location" msgid="3788275734953323491">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+    <string name="permgrouprequest_location" msgid="3788275734953323491">"ఈ పరికరం యొక్క లొకేషన్‌ను యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
     <string name="permgrouprequestdetail_location" msgid="1347189607421252902">"మీరు యాప్‌ను ఉపయోగిస్తున్నప్పుడు మాత్రమే స్థానానికి యాప్ యాక్సెస్ కలిగి ఉంటుంది"</string>
-    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"ఈ పరికర స్థానాన్ని &lt;b&gt;అన్ని సమయాలలో&lt;/b&gt; యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
+    <string name="permgroupbackgroundrequest_location" msgid="5039063878675613235">"ఈ పరికరం యొక్క లొకేషన్‌ను &lt;b&gt;అన్ని సమయాలలో&lt;/b&gt; యాక్సెస్ చేయడానికి &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;ను అనుమతించాలా?"</string>
     <string name="permgroupbackgroundrequestdetail_location" msgid="4597006851453417387">"యాప్ ప్రస్తుతం మీరు ఆ యాప్‌ను ఉపయోగిస్తున్నప్పుడు మాత్రమే స్థానాన్ని యాక్సెస్ చేయగలుగుతుంది"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"క్యాలెండర్"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"మీ క్యాలెండర్‌ను యాక్సెస్ చేయడానికి"</string>
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"అలారం ధ్వనులు"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"నోటిఫికేషన్ ధ్వనులు"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"తెలియదు"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి</item>
-      <item quantity="one">Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">ఓపెన్ Wi-Fi నెట్‌వర్క్‌లు అందుబాటులో ఉన్నాయి</item>
-      <item quantity="one">ఓపెన్ Wi-Fi నెట్‌వర్క్ అందుబాటులో ఉంది</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"బహిరంగ Wi‑Fi నెట్‌వర్క్‌కు కనెక్ట్ చేయండి"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi నెట్‌వర్క్‌కి కనెక్ట్ చేస్తోంది"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi నెట్‌వర్క్‌కు కనెక్ట్ చేయబడింది"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi‑Fi నెట్‌వర్క్‌కు కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"అన్ని నెట్‌వర్క్‌లు చూడటానికి నొక్కండి"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"కనెక్ట్ చేయి"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"అన్ని నెట్‌వర్క్‌లు"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"సూచించిన Wi‑Fi నెట్‌వర్క్‌లను అనుమతించాలా?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> సూచించిన నెట్‌వర్క్‌లు. పరికరం ఆటోమేటిక్‌గా కనెక్ట్ అవచ్చు."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"అనుమతించు"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"వద్దు"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi స్వయంచాలకంగా ఆన్ అవుతుంది"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"మీరు అధిక నాణ్యత గల సేవ్ చేసిన నెట్‌వర్క్‌కు సమీపంగా ఉన్నప్పుడు"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"తిరిగి ఆన్ చేయవద్దు"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi స్వయంచాలకంగా ఆన్ చేయబడింది"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"మీరు సేవ్ చేసిన నెట్‌వర్క్‌కి సమీపంలో ఉన్నారు: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"కనెక్ట్ చేయబడింది"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> పరిమిత కనెక్టివిటీని కలిగి ఉంది"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"ఏదేమైనా కనెక్ట్ చేయడానికి నొక్కండి"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"మీ హాట్‌స్పాట్ సెట్టింగ్‌లకు మార్పులు"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"మీ హాట్‌స్పాట్ బ్యాండ్ మార్చబడింది."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"ఈ పరికరం 5GHz కోసం మాత్రమే మీ ప్రాధాన్యతకు మద్దతు ఇవ్వదు. బదులుగా, ఈ పరికరం అందుబాటులో ఉన్నప్పుడు 5GHz బ్యాండ్‌ను ఉపయోగిస్తుంది."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>కి మార్చబడింది"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"పరికరం <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>కి ఇంటర్నెట్ యాక్సెస్ లేనప్పుడు <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ని ఉపయోగిస్తుంది. ఛార్జీలు వర్తించవచ్చు."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> నుండి <xliff:g id="NEW_NETWORK">%2$s</xliff:g>కి మార్చబడింది"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"తెలియని నెట్‌వర్క్ రకం"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiకి కనెక్ట్ చేయడం సాధ్యపడలేదు"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"కనెక్షన్‌ని అనుమతించాలా?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s యాప్ %2$s Wifi నెట్‌వర్క్‌కు కనెక్ట్ చేయాలనుకుంటోంది"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ఒక యాప్"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directను ప్రారంభించండి. దీని వలన Wi-Fi క్లయింట్/హాట్‌స్పాట్ ఆపివేయబడుతుంది."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directను ప్రారంభించడం సాధ్యపడలేదు."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ఆన్‌లో ఉంది"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"సెట్టింగ్‌ల కోసం నొక్కండి"</string>
     <string name="accept" msgid="1645267259272829559">"ఆమోదిస్తున్నాను"</string>
     <string name="decline" msgid="2112225451706137894">"తిరస్కరిస్తున్నాను"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ఆహ్వానం పంపబడింది"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"కనెక్ట్ చేయడానికి ఆహ్వానం"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"వీరి నుండి:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"వీరికి:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"అవసరమైన పిన్‌ను టైప్ చేయండి:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"పిన్‌:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"టాబ్లెట్ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కు కనెక్ట్ చేయబడినప్పుడు Wi-Fi నుండి తాత్కాలికంగా డిస్‌కనెక్ట్ చేయబడుతుంది"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"మీ Android TV పరికరం <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి కనెక్ట్ అయి ఉన్నప్పుడు తాత్కాలికంగా Wi-Fi నుండి డిస్‌కనెక్ట్ అవుతుంది"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"ఫోన్ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>కి కనెక్ట్ అయినప్పుడు అది Wi-Fi నుండి తాత్కాలికంగా డిస్‌కనెక్ట్ చేయబడుతుంది"</string>
     <string name="select_character" msgid="3365550120617701745">"అక్షరాన్ని చొప్పించండి"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS సందేశాలు పంపుతోంది"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; పెద్ద సంఖ్యలో SMS సందేశాలను పంపుతోంది. సందేశాలను పంపడం కొనసాగించడానికి మీరు ఈ యాప్‌ను అనుమతించాలనుకుంటున్నారా?"</string>
@@ -1818,8 +1771,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"బ్యాటరీ జీవిత కాలాన్ని మరింత పొడిగించేందుకు, నేపథ్య కార్యకలాపం, కొన్ని దృశ్య ప్రభావాలు, అలాగే అధిక శక్తిని వినియోగించే ఇతర ఫీచర్‌లను బ్యాటరీ సేవర్ ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది. "<annotation id="url">"మరింత తెలుసుకోండి"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"బ్యాటరీ జీవిత కాలాన్ని మరింత పొడిగించేందుకు, నేపథ్య కార్యకలాపం, కొన్ని దృశ్య ప్రభావాలు, అలాగే అధిక శక్తిని వినియోగించే ఇతర ఫీచర్‌లను బ్యాటరీ సేవర్ ఆఫ్ చేస్తుంది లేదా పరిమితం చేస్తుంది."</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2052,4 +2007,23 @@
     </plurals>
     <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 fd77532..ff1ea21 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"เสียงปลุก"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"เสียงการแจ้งเตือน"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"ไม่รู้จัก"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">มีหลายเครือข่าย Wi-Fi ที่ใช้งานได้</item>
-      <item quantity="one">มี 1 เครือข่าย Wi-Fi ที่ใช้งานได้</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">มีหลายเครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
-      <item quantity="one">มี 1 เครือข่าย Wi-Fi สาธารณะที่ใช้งานได้</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"เชื่อมต่อเครือข่าย Wi‑Fi แบบเปิด"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"กำลังเชื่อมต่อกับเครือข่าย Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"เชื่อมต่อเครือข่าย Wi-Fi แล้ว"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"ไม่สามารถเชื่อมต่อเครือข่าย Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"แตะเพื่อดูเครือข่ายทั้งหมด"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"เชื่อมต่อ"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"เครือข่ายทั้งหมด"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"อนุญาตให้เชื่อมต่อเครือข่าย Wi-Fi ที่แนะนำไหม"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"เครือข่ายที่แนะนำโดย <xliff:g id="NAME">%s</xliff:g> และอุปกรณ์อาจเชื่อมต่อโดยอัตโนมัติ"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"อนุญาต"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"ไม่เป็นไร"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi จะเปิดโดยอัตโนมัติ"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"เมื่อคุณอยู่ใกล้เครือข่ายคุณภาพสูงที่บันทึกไว้"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"ไม่ต้องเปิดอีกครั้ง"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"เปิด Wi‑Fi โดยอัตโนมัติแล้ว"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"คุณอยู่ใกล้เครือข่ายที่บันทึกไว้ ซึ่งก็คือ <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"ลงชื่อเข้าใช้เครือข่าย WiFi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"ลงชื่อเข้าใช้เครือข่าย"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"เชื่อมต่อแล้ว"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> มีการเชื่อมต่อจำกัด"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"แตะเพื่อเชื่อมต่อ"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"มีการเปลี่ยนแปลงการตั้งค่าฮอตสปอต"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"ย่านความถี่ฮอตสปอตมีการเปลี่ยนแปลง"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"อุปกรณ์นี้ไม่รองรับค่ากำหนดของคุณเฉพาะสำหรับ 5 GHz เท่านั้น และจะใช้ย่านความถี่ 5 GHz แทน เมื่อใช้ได้"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"เปลี่ยนเป็น <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"อุปกรณ์จะใช้ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> เมื่อ <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> เข้าถึงอินเทอร์เน็ตไม่ได้ โดยอาจมีค่าบริการ"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"เปลี่ยนจาก <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> เป็น <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"ประเภทเครือข่ายที่ไม่รู้จัก"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ WiFi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"อนุญาตการเชื่อมต่อใช่ไหม"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"แอปพลิเคชัน %1$s ต้องการเชื่อมต่อเครือข่าย Wi-Fi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"แอปพลิเคชัน"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ไม่สามารถเริ่ม WiFi Direct ได้"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด WiFi Direct อยู่"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"แตะเพื่อดูการตั้งค่า"</string>
     <string name="accept" msgid="1645267259272829559">"ยอมรับ"</string>
     <string name="decline" msgid="2112225451706137894">"ปฏิเสธ"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ส่งข้อความเชิญแล้ว"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ข้อความเชิญเพื่อเชื่อมต่อ"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"จาก:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"ถึง:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"แท็บเล็ตนี้จะยกเลิกการเชื่อมต่อกับ WiFi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"อุปกรณ์ Android TV จะยกเลิกการเชื่อมต่อ Wi-Fi ชั่วคราวระหว่างที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"โทรศัพท์จะยกเลิกการเชื่อมต่อกับ WiFi ชั่วคราวในขณะที่เชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; กำลังส่งข้อความ SMS จำนวนมาก คุณต้องการอนุญาตให้แอปพลิเคชันนี้ส่งข้อความต่อหรือไม่"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"โหมดประหยัดแบตเตอรี่จะปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์ที่ใช้พลังงานมากอื่นๆ เพื่อยืดอายุการใช้งานแบตเตอรี่ "<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"โหมดประหยัดแบตเตอรี่จะปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์ที่ใช้พลังงานมากอื่นๆ เพื่อยืดอายุการใช้งานแบตเตอรี่"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 3e71d77..79c040f 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Mga tunog ng alarm"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Mga tunog ng notification"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Hindi Alam"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Available ang mga Wi-Fi network</item>
-      <item quantity="other">Available ang mga Wi-Fi network</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Available ang mga bukas na Wi-Fi network</item>
-      <item quantity="other">Available ang mga bukas na Wi-Fi network</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Kumonekta sa bukas na Wi‑Fi network"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Kumokonekta sa Wi‑Fi network"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Nakakonekta sa Wi‑Fi network"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Hindi makakonekta sa Wi‑Fi network"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"I-tap upang makita ang lahat ng network"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Kumonekta"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Lahat ng network"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Payagan ang mga iminumungkahing Wi‑Fi network?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Mga iminumungkahing network ng <xliff:g id="NAME">%s</xliff:g>. Posibleng awtomatikong kumonekta ang device."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Payagan"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Hindi, salamat na lang"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Awtomatikong mag-o-on ang Wi‑Fi"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Kapag malapit ka sa naka-save na network na mataas ang kalidad"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Huwag i-on muli"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Awtomatikong na-on ang Wi‑Fi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Malapit ka sa isang naka-save na network: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Mag-sign in sa Wi-Fi network"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Mag-sign in sa network"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Nakakonekta"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Limitado ang koneksyon ng <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"I-tap para kumonekta pa rin"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Mga pagbabago sa mga setting ng iyong hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Nagbago ang band ng iyong hotspot."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Hindi sinusuportahan ng device na ito ang kagustuhan mong gumamit lang ng 5GHz. Sa halip, gagamitin ng device na ito ang 5GHz na band kapag available."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Lumipat sa <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Ginagamit ng device ang <xliff:g id="NEW_NETWORK">%1$s</xliff:g> kapag walang access sa internet ang <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>. Maaaring may mga malapat na singilin."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Lumipat sa <xliff:g id="NEW_NETWORK">%2$s</xliff:g> mula sa <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"isang hindi kilalang uri ng network"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" ay mayroong mahinang koneksyon sa internet."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Payagan ang kuneksyon?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Gustong kumonekta ng application na %1$s sa Wifi Network na %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Isang application"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Hindi masimulan ang Wi-Fi Direct"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"I-tap para sa mga setting"</string>
     <string name="accept" msgid="1645267259272829559">"Tanggapin"</string>
     <string name="decline" msgid="2112225451706137894">"Tanggihan"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Naipadala ang imbitasyon"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Imbitasyong kumonekta"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Mula kay:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kay:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Pansamantalang madidiskoneta ang tablet sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Pansamantalang madidiskonekta sa Wi-Fi ang iyong Android TV device habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Pansamantalang madidiskoneta ang telepono sa Wi-Fi habang nakakonekta ito sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Ang &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ay nagpapadala ng maraming mensaheng SMS. Gusto mo bang payagan ang app na ito na magpatuloy sa pagpapadala ng mga mensahe?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Ino-off o pinaghihigpitan ng Pangtipid sa Baterya ang aktibidad sa background, ilang visual effect, at iba pang feature na malakas kumonsumo ng baterya para mapatagal ang baterya. "<annotation id="url">"Matuto Pa"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Ino-off o pinaghihigpitan ng Pangtipid sa Baterya ang aktibidad sa background, ilang visual effect, at iba pang feature na malakas kumonsumo ng baterya para mapatagal ang baterya."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 8a63348..d6841f0 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Alarm sesleri"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirim sesleri"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Bilinmiyor"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Kablosuz ağlar var</item>
-      <item quantity="one">Kablosuz ağ var</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Kullanılabilir Kablosuz ağları aç</item>
-      <item quantity="one">Kullanılabilir Kablosuz ağı aç</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Açık kablosuz ağa bağlanın"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Kablosuz ağa bağlanıyor"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Kablosuz ağa bağlanıldı"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Kablosuz ağa bağlanamadı"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Tüm ağları görmek için dokunun"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Bağlan"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Tüm ağlar"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Önerilen kablosuz ağlara izin verilsin mi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> tarafından önerilen ağlar. Cihaz otomatik olarak bağlanabilir."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"İzin ver"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Hayır, teşekkürler"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Kablosuz özelliği otomatik olarak açılacak"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Daha önce kaydedilmiş yüksek kaliteli bir ağın yakınında olduğunuzda"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Tekrar açılmasın"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Kablosuz ağ otomatik olarak açıldı"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Kayıtlı bir ağın yakınındasınız: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Kablosuz ağda oturum açın"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ağda oturum açın"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Bağlandı"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> sınırlı bağlantıya sahip"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Yine de bağlanmak için dokunun"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot ayarlarınız değişti"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot bandı değişti."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Bu cihaz yalnızca 5 GHz bandının kullanılmasına yönelik tercihinizi desteklemiyor. Bunun yerine, bu cihaz 5 GHz bandını mevcut olduğunda kullanacak."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> ağına geçildi"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> ağının internet erişimi olmadığında cihaz <xliff:g id="NEW_NETWORK">%1$s</xliff:g> ağını kullanır. Bunun için ödeme alınabilir."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> ağından <xliff:g id="NEW_NETWORK">%2$s</xliff:g> ağına geçildi"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"bilinmeyen ağ türü"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" internet bağlantısı zayıf."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Bağlantıya izin verilsin mi?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s uygulaması %2$s Kablosuz Ağına bağlanmak istiyor"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Bir uygulama"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantı\'yı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan Bağlantı başlatılamadı."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan Bağlantı özelliği açık"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Ayarlar için dokunun"</string>
     <string name="accept" msgid="1645267259272829559">"Kabul et"</string>
     <string name="decline" msgid="2112225451706137894">"Reddet"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Davetiye gönderildi"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Bağlantı davetiyesi"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Gönderen:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Alıcı:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Tablet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV cihazınız <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken kablosuz ağ bağlantısı geçici olarak kesilecek"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g> adlı cihaza bağlıyken Kablosuz ağ bağlantısı geçici olarak kesilecektir"</string>
     <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS iletileri gönderiliyor"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; çok sayıda SMS iletisi gönderiyor. Bu uygulamanın ileti göndermeye devam etmesine izin veriyor musunuz?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Pil Tasarrufu, pil ömrünü uzatmak için arka plan etkinliğini, bazı görsel efektleri ve güç tüketimi fazla olan diğer özellikleri kapatır veya sınırlandırır. "<annotation id="url">"Daha Fazla Bilgi"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Pil Tasarrufu, pil ömrünü uzatmak için arka plan etkinliğini, bazı görsel efektleri ve güç tüketimi fazla olan diğer özellikleri kapatır veya sınırlandırır."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 3d7358e..3412eb2 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1284,34 +1284,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Сигнали будильника"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Сигнали сповіщень"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Невідомо"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Мережі Wi-Fi доступні</item>
-      <item quantity="few">Мережі Wi-Fi доступні</item>
-      <item quantity="many">Мережі Wi-Fi доступні</item>
-      <item quantity="other">Мережі Wi-Fi доступні</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Відкриті мережі Wi-Fi доступні</item>
-      <item quantity="few">Відкриті мережі Wi-Fi доступні</item>
-      <item quantity="many">Відкриті мережі Wi-Fi доступні</item>
-      <item quantity="other">Відкриті мережі Wi-Fi доступні</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Під’єднайтеся до відкритої мережі Wi-Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"З’єднання з мережею Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Під’єднано до мережі Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Торкніться, щоб побачити всі мережі"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Під’єднатися"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Усі мережі"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Дозволити пропоновані мережі Wi‑Fi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Мережі, пропоновані додатком <xliff:g id="NAME">%s</xliff:g>. Пристрій може підключитися автоматично."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Дозволити"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Ні, дякую"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi вмикатиметься автоматично"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Коли ви поблизу збереженої мережі високої якості"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Не вмикати знову"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"З’єднання Wi-Fi увімкнулось автоматично"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Ви поблизу збереженої мережі: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Вхід у мережу Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Вхід у мережу"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1324,9 +1296,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Підключено"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"Підключення до мережі <xliff:g id="NETWORK_SSID">%1$s</xliff:g> обмежено"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Натисніть, щоб усе одно підключитися"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Зміни в налаштуваннях точки доступу"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Діапазон точки доступу змінено."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"На цьому пристрої не підтримується налаштування лише 5 ГГц. Замість цього буде використовуватися діапазон 5 ГГц, якщо доступно."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Пристрій перейшов на мережу <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Коли мережа <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> не має доступу до Інтернету, використовується <xliff:g id="NEW_NETWORK">%1$s</xliff:g>. Може стягуватися плата."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Пристрій перейшов з мережі <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> на мережу <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1338,27 +1307,8 @@
     <item msgid="8257233890381651999">"Мережа VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"невідомий тип мережі"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" має погане з’єднання з Інтернетом."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дозволити з’єднання?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Додаток %1$s хоче під’єднатися до мережі Wi-Fi \"%2$s\""</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Додаток"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не вдалося запустити Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Торкніться, щоб відкрити налаштування"</string>
     <string name="accept" msgid="1645267259272829559">"Прийняти"</string>
     <string name="decline" msgid="2112225451706137894">"Відхилити"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрошення надіслано"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Запрошення під’єднатися"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Від:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> планшетний ПК тимчасово від’єднається від мережі Wi-Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"На час підключення до пристрою <xliff:g id="DEVICE_NAME">%1$s</xliff:g> Android TV тимчасово відключиться від мережі Wi-Fi"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Під час з’єднання з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g> телефон тимчасово від’єднається від мережі Wi-Fi"</string>
     <string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Програма &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; надсилає велику кількість SMS-повідомлень. Дозволити цій програмі й надалі надсилати повідомлення?"</string>
@@ -1867,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Режим енергозбереження припиняє або обмежує фонову активність і вимикає деякі візуальні ефекти й інші енергозатратні функції, щоб подовжити час роботи акумулятора. "<annotation id="url">"Докладніше"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Режим енергозбереження припиняє або обмежує фонову активність і вимикає деякі візуальні ефекти й інші енергозатратні функції, щоб подовжити час роботи акумулятора."</string>
+    <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>
@@ -2123,4 +2073,23 @@
     </plurals>
     <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 97660b4..003fd54 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"الارم کی آوازیں"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"اطلاعات کی آوازیں"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"نامعلوم"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">‏Wi-Fi نیٹ ورکس دستیاب ہیں</item>
-      <item quantity="one">‏Wi-Fi نیٹ ورک دستیاب ہے</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">‏عوامی Wi-Fi نیٹ ورکس دستیاب ہیں</item>
-      <item quantity="one">‏عوامی Wi-Fi نیٹ ورک دستیاب ہے</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"‏عوامی Wi‑Fi نیٹ ورک سے منسلک ہوں"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"‏Wi‑Fi نیٹ ورک سے منسلک ہو رہا ہے"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"‏عوامی Wi‑Fi نیٹ ورک سے منسلک ہو گيا"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"‏Wi‑Fi نیٹ ورک سے منسلک نہیں ہو سکا"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"تمام نیٹ ورکس دیکھنے کیلئے تھپتھپائيں"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"منسلک کریں"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"سبھی نیٹ ورکس"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"‏تجویز کردہ Wi‑Fi نیٹ ورکس کو اجازت دیں؟"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> تجویز کردہ نیٹ ورکس۔ آلہ خودکار طور پر منسلک ہو سکتا ہے۔"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"اجازت ہیں"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"نہیں شکریہ"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"‏Wi‑Fi از خود آن ہو جائے گا"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"جب آپ اعلی معیار کے محفوظ کردہ نیٹ ورک کے قریب ہوں"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"دوبارہ آن نہ کریں"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"‏Wi-Fi خود کار طور پر آن ہو گیا"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"آپ ایک محفوظ نیٹ ورک کے قریب ہیں: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"‏Wi-Fi نیٹ ورک میں سائن ان کریں"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"نیٹ ورک میں سائن ان کریں"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"منسلک ہے"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> کی کنیکٹوٹی محدود ہے"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"بہر حال منسلک کرنے کے لیے تھپتھپائیں"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"اپنے ہاٹ اسپاٹ کی ترتیبات میں تبدیلیاں"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"آپ کا ہاٹ اسپات بینڈ تبدیل ہو گیا۔"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"‏یہ آلہ صرف 5GHz کے لئے آپ کی ترجیح کا تعاون نہیں کرے گا۔ بلکہ 5GHz بینڈ کے دستیاب ہونے پر اس کا استعمال کرے گا۔"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> پر سوئچ ہو گیا"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"جب <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> کو انٹرنیٹ تک رسائی نہیں ہوتی ہے تو آلہ <xliff:g id="NEW_NETWORK">%1$s</xliff:g> کا استعمال کرتا ہے۔ چارجز لاگو ہو سکتے ہیں۔"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> سے <xliff:g id="NEW_NETWORK">%2$s</xliff:g> پر سوئچ ہو گیا"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"نیٹ ورک کی نامعلوم قسم"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"‏Wi-Fi سے مربوط نہیں ہو سکا"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"کنکشن کی اجازت دیں؟"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"‏ایپلیکیشن ‎%1$s Wifi نیٹ ورک ‎%2$s سے منسلک ہونا چاہتی ہے"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"ایک ایپلیکیشن"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"‏Wi-Fi ڈائریکٹ"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"‏Wi-Fi ڈائرکٹ شروع کریں۔ یہ Wi-Fi کلائنٹ/ہاٹ اسپاٹ کو آف کردے گا۔"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"‏Wi-Fi ڈائرکٹ شروع نہیں کرسکا۔"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"‏Wi-Fi Direct آن ہے"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"ترتیبات کیلئے تھپتھپائیں"</string>
     <string name="accept" msgid="1645267259272829559">"قبول کریں"</string>
     <string name="decline" msgid="2112225451706137894">"مسترد کریں"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"دعوت بھیج دی گئی"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"مربوط ہونے کی دعوت"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"منجانب:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"بنام:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"‏مطلوبہ PIN ٹائپ کریں:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"‏ٹیبلیٹ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے مربوط ہونے پر عارضی طور پر Wi-Fi سے منقطع ہو جائے گا"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"‏آپ کا Android TV آلہ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے منسلک ہونے پر عارضی طور پر Wi-Fi سے غیر منسلک ہو جائے گا"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"‏فون <xliff:g id="DEVICE_NAME">%1$s</xliff:g> سے مربوط رہنے کے وقت عارضی طور پر Wi-Fi سے منقطع ہوجائے گا"</string>
     <string name="select_character" msgid="3365550120617701745">"حرف داخل کریں"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"‏SMS پیغامات بھیج رہا ہے"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"‏&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; بڑی تعداد میں SMS پیغامات بھیج رہی ہے۔ کیا آپ اس ایپ کو پیغامات بھیجتے رہنے کی اجازت دینا چاہتے ہیں؟"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"بیٹری سیور بیٹری لائف کو بڑھانے کے لیے پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر اعلی قوت والی خصوصیات کو آف یا محدود کرتی ہے۔ "<annotation id="url">"مزید جانیں"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"بیٹری سیور بیٹری لائف کو بڑھانے کے لیے پس منظر کی سرگرمی، کچھ بصری اثرات اور دیگر اعلی قوت والی خصوصیات کو آف یا محدود کرتی ہے۔"</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 1f70155..83e99b9 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Signal ovozlari"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Bildirishnoma ovozlari"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Noma’lum"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Wi-Fi tarmoqlari aniqlandi</item>
-      <item quantity="one">Wi-Fi tarmog‘i aniqlandi</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Ochiq Wi-Fi tarmoqlari aniqlandi</item>
-      <item quantity="one">Ochiq Wi-Fi tarmog‘i aniqlandi</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Ochiq Wi‑Fi tarmoqqa ulaning"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Wi‑Fi tarmoqqa ulanmoqda"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Wi‑Fi tarmoqqa ulanildi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Wi-Fi tarmoqqa ulanib bo‘lmadi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Barcha tarmoqlarni ko‘rish uchun bosing"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Ulanish"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Barcha tarmoqlar"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Tavsiya qilingan Wi‑Fi tarmoqlarga ruxsat berilsinmi?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> tavsiya qilgan tarmoqlar. Qurilma avtomatik ulanishi mumkin."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Ruxsat"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Kerak emas"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi avtomatik ravishda yoqiladi"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Saqlangan tarmoqlar ichidan signali yaxshisi hududida ekaningizda"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Qayta yoqilmasin"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi‑Fi avtomatik ravishda yoqildi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Saqlangan tarmoq atrofidasiz: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Wi-Fi tarmoqqa kirish"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Tarmoqqa kirish"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Ulandi"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> nomli tarmoqda aloqa cheklangan"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Baribir ulash uchun bosing"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Hotspot sozlamalari o‘zgartirildi"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Hotspot chastotasi o‘zgartirildi."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Qurilma faqat 5 GGs chastotada ishlay olmaydi. Bu chastotadan imkoniyatga qarab foydalaniladi."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"<xliff:g id="NETWORK_TYPE">%1$s</xliff:g> tarmog‘iga ulanildi"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Agar <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> tarmoqda internet uzilsa, qurilma <xliff:g id="NEW_NETWORK">%1$s</xliff:g>ga ulanadi. Sarflangan trafik uchun haq olinishi mumkin."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> tarmog‘idan <xliff:g id="NEW_NETWORK">%2$s</xliff:g> tarmog‘iga o‘tildi"</string>
@@ -1294,28 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"noma’lum tarmoq turi"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi’ga ulana olmadi"</string>
-    <!-- no translation found for wifi_watchdog_network_disabled_detailed (4917472096696322767) -->
-    <skip />
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Ulanishga ruxsat berilsinmi?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"%1$s ilovasi %2$s Wi-Fi tarmog‘iga ulanmoqchi"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ilova"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct’ni ishga tushirish. Bu Wi-Fi mijoz/ulanish nuqtasini o‘chiradi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ishga tushirilmadi."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct yoniq"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Sozlamalarni ochish uchun bosing"</string>
     <string name="accept" msgid="1645267259272829559">"Qabul qilish"</string>
     <string name="decline" msgid="2112225451706137894">"Rad etish"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"taklif jo‘natildi"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"ulanish taklifi"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kimdan:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kimga:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"So‘ralgan PIN kodni kiriting:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kod:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Planshet <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ga ulanganligi tufayli vaqtincha Wi-Fi tarmog‘idan uzildi."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV qurilmangiz <xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulangani uchun u vaqtincha Wi-Fi tarmoqdan uzildi."</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Telefon <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ga ulanganligi tufayli vaqtincha Wi-Fi tarmog‘idan uzildi."</string>
     <string name="select_character" msgid="3365550120617701745">"Belgilarni kiriting"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"SMS xabarlar yuborilmoqda"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; katta miqdordagi SMS xabarlarini jo‘natmoqda. Ushbu ilovaga xabarlar jo‘natishni davom ettirishga ruxsat berasizmi?"</string>
@@ -1818,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Quvvat tejash rejimi batareya quvvatini kengaytirish uchun fondagi harakatlarni, ayrim vizual effektlarni hamda koʻproq quvvat talab qiluvchi funksiyalarni faolsizlantiradi yoki cheklaydi. "<annotation id="url">"Batafsil"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Quvvat tejash rejimi batareya quvvatini kengaytirish uchun fondagi harakatlarni, ayrim vizual effektlarni hamda koʻproq quvvat talab qiluvchi funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
+    <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>
@@ -2052,4 +2005,23 @@
     </plurals>
     <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 dc9076f..7b17de7 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Âm thanh báo thức"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Âm thanh thông báo"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Không xác định"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">Các mạng Wi-Fi khả dụng</item>
-      <item quantity="one">Mạng Wi-Fi khả dụng</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">Mở các mạng Wi-Fi khả dụng</item>
-      <item quantity="one">Mở mạng Wi-Fi khả dụng</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Kết nối với mạng Wi-Fi đang mở"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Đang kết nối với mạng Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Đã kết nối với mạng Wi-Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Không thể kết nối với mạng Wi‑Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Nhấn để xem tất cả các mạng"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Kết nối"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Tất cả các mạng"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Cho phép các mạng Wi‑Fi được đề xuất?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"Các mạng do <xliff:g id="NAME">%s</xliff:g> đề xuất. Thiết bị có thể kết nối tự động."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Cho phép"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Không, cảm ơn"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi sẽ tự động bật"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Khi bạn ở gần mạng đã lưu chất lượng cao"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Không bật lại"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"Wi-Fi đã tự động bật"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Bạn đang ở gần mạng đã lưu: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Đăng nhập vào mạng Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Đăng nhập vào mạng"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Đã kết nối"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> có khả năng kết nối giới hạn"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Nhấn để tiếp tục kết nối"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Những thay đổi trong mục cài đặt điểm phát sóng của bạn"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Bằng tần của điểm phát sóng đã thay đổi."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Thiết bị này không hỗ trợ tùy chọn chỉ sử dụng băng tần 5 GHz. Thay vào đó, thiết bị này sẽ sử dụng băng tần 5 GHz khi có thể."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Đã chuyển sang <xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Thiết bị sử dụng <xliff:g id="NEW_NETWORK">%1$s</xliff:g> khi <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> không có quyền truy cập Internet. Bạn có thể phải trả phí."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Đã chuyển từ <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> sang <xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"loại mạng không xác định"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" có kết nối internet kém."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Cho phép kết nối?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Ứng dụng %1$s muốn kết nối với Mạng Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Ứng dụng"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Không thể khởi động Wi-Fi Direct."</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Nhấn để xem cài đặt"</string>
     <string name="accept" msgid="1645267259272829559">"Đồng ý"</string>
     <string name="decline" msgid="2112225451706137894">"Từ chối"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Đã gửi thư mời"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Thư mời kết nối"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Người gửi:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Người nhận:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Máy tính bảng sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi máy tính bảng được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Thiết bị Android TV sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Điện thoại sẽ tạm thời ngắt kết nối khỏi Wi-Fi trong khi điện thoại được kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; đang gửi rất nhiều tin nhắn SMS. Bạn có muốn cho phép ứng dụng này tiếp tục gửi tin nhắn không?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Trình tiết kiệm pin tắt hoặc hạn chế hoạt động trong nền, một số hiệu ứng hình ảnh và tính năng công suất cao khác để kéo dài thời lượng pin. "<annotation id="url">"Tìm hiểu thêm"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Trình tiết kiệm pin tắt hoặc hạn chế hoạt động trong nền, một số hiệu ứng hình ảnh và tính năng công suất cao khác để kéo dài thời lượng pin."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 8ab182e..e29898f 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"闹钟提示音"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"通知提示音"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"未知"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">有可用的 WLAN 网络</item>
-      <item quantity="one">有可用的 WLAN 网络</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">有可用的开放 WLAN 网络</item>
-      <item quantity="one">有可用的开放 WLAN 网络</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"连接到开放的 WLAN 网络"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"正在连接到 WLAN 网络"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"已连接到 WLAN 网络"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"无法连接到 WLAN 网络"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"点按即可查看所有网络"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"连接"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"所有网络"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"是否允许系统连接到建议的 WLAN 网络?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g>建议的网络。设备可能会自动连接到这些网络。"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"允许"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"不用了"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"WLAN 将自动开启"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"当您位于已保存的高品质网络信号范围内时"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"不要重新开启"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"已自动开启 WLAN 网络"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"您位于已保存的网络 (<xliff:g id="NETWORK_SSID">%1$s</xliff:g>) 信号范围内"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登录到WLAN网络"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登录到网络"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已连接"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的连接受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"点按即可继续连接"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"您的热点设置已变更"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"您的热点频段已变更。"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"此设备不支持您的偏好设置(仅限 5GHz),而且会在 5GHz 频段可用时使用该频段。"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"已切换至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"设备会在<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>无法访问互联网时使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g>(可能需要支付相应的费用)。"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"已从<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切换至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"未知网络类型"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到WLAN"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 互联网连接状况不佳。"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"要允许连接吗?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"“%1$s”应用想要连接到 WLAN 网络“%2$s”"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"一款应用"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WLAN 直连"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动WLAN直连。此操作将会关闭WLAN客户端/热点。"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动WLAN直连。"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用WLAN直连"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"点按即可查看相关设置"</string>
     <string name="accept" msgid="1645267259272829559">"接受"</string>
     <string name="decline" msgid="2112225451706137894">"拒绝"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"已发出邀请"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"连接邀请"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"发件人:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件人:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"输入所需的PIN码:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN 码:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"平板电脑连接到“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”时会暂时断开与WLAN的连接"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"当 Android TV 设备连接到 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 时,它会暂时断开 WLAN 连接"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"手机连接到<xliff:g id="DEVICE_NAME">%1$s</xliff:g>时会暂时断开与WLAN的连接。"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字符"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt;在发送大量短信。是否允许该应用继续发送短信?"</string>
@@ -1817,8 +1771,10 @@
     <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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"省电模式会关闭或限制后台活动、部分视觉效果及其他耗电高的功能,以延长电池续航时间。"<annotation id="url">"了解详情"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"省电模式会关闭或限制后台活动、部分视觉效果及其他耗电高的功能,以延长电池续航时间。"</string>
+    <!-- no translation found for battery_saver_description_with_learn_more (1002571337088673987) -->
+    <skip />
+    <!-- no translation found for battery_saver_description (2307555792915978653) -->
+    <skip />
     <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>
@@ -2051,4 +2007,23 @@
     </plurals>
     <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 d318764..40f0c94 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"鬧鐘音效"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"通知音效"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"不明"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">有可用的 Wi-Fi 網絡</item>
-      <item quantity="one">有可用的 Wi-Fi 網絡</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">有可用的公開 Wi-Fi 網絡</item>
-      <item quantity="one">有可用的公開 Wi-Fi 網絡</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"連線至開放的 Wi-Fi 網絡"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"正在連線至 Wi-Fi 網絡"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"已連線至 Wi-Fi 網絡"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"無法連線至 Wi-Fi 網絡"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"輕按即可查看所有網絡"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"連線"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"所有網絡"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"要允許連線至建議的 Wi-Fi 網絡嗎?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"「<xliff:g id="NAME">%s</xliff:g>」已建議網絡連線,裝置可能會自動連接網絡。"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"允許"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"不用了,謝謝"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi-Fi 將會自動開啟"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"當您位於已儲存的高品質網絡信號範圍內時"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"不要重新開啟"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"已自動開啟 Wi‑Fi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"您附近有已儲存的網絡:<xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網絡"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登入網絡"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已連接"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g>連線受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"仍要輕按以連結至此網絡"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"您的熱點設定變更"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"您的熱點頻段已變更。"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"此裝置不支援只限 5 GHz 的偏好設定,但會在 5 GHz 頻段可用時採用。"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在 <xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> 無法連線至互聯網時使用<xliff:g id="NEW_NETWORK">%1$s</xliff:g> (可能需要支付相關費用)。"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g>切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明網絡類型"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 互聯網連線欠佳。"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"應用程式 %1$s 要求連線至 WiFi 網絡 %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct,這會關閉 Wi-Fi 使用者端/熱點。"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 Wi-Fi Direct。"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"輕按即可設定"</string>
     <string name="accept" msgid="1645267259272829559">"接受"</string>
     <string name="decline" msgid="2112225451706137894">"拒絕"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"已發出邀請"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"連線邀請"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"寄件者:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件者:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN 碼:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN 碼:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"平板電腦與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV 裝置與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間,系統將暫時中斷 Wi-Fi 連線"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字元"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"正在傳送 SMS 短訊"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;/b&gt;正在傳送大量短訊。您要允許這個應用程式繼續傳送短訊嗎?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"省電模式會關閉或限制背景活動、某些視覺效果以及其他高耗電功能,以延長電池壽命。"<annotation id="url">"瞭解詳情"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"「省電模式」會關閉或限制背景活動、某些視覺效果和其他耗電量高的功能,以延長電池壽命。"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 cd787c0..2fb155e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"鬧鐘音效"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"通知音效"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"不明"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="other">有多個可用的 Wi-Fi 網路</item>
-      <item quantity="one">有一個可用的 Wi-Fi 網路</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="other">有多個可用的開放 Wi-Fi 網路</item>
-      <item quantity="one">有多個可用的開放 Wi-Fi 網路</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"連線至開放的 Wi‑Fi 網路"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"正在連線至 Wi‑Fi 網路"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"已連線至 Wi-Fi 網路"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"無法連線至 Wi‑Fi 網路"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"輕觸即可查看所有網路"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"連線"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"所有網路"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"是否允許系統連線到建議的 Wi‑Fi 網路?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"「<xliff:g id="NAME">%s</xliff:g>」建議的網路。裝置可能會自動連線到這些網路。"</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"允許"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"不用了,謝謝"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"Wi‑Fi 將自動開啟"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"當你位於已儲存的高品質網路範圍內時"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"不要重新開啟"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"已自動開啟 Wi‑Fi"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"你位於已儲存的網路範圍內:<xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"登入 Wi-Fi 網路"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"登入網路"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"已連線"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"<xliff:g id="NETWORK_SSID">%1$s</xliff:g> 的連線能力受限"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"輕觸即可繼續連線"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"無線基地台設定變更"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"你的無線基地台頻帶已變更。"</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"這個裝置不支援你的偏好設定 (僅限 5GHz),而是會在 5GHz 可用時使用該頻帶。"</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"已切換至<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"裝置會在無法連上「<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g>」時切換至「<xliff:g id="NEW_NETWORK">%1$s</xliff:g>」(可能需要支付相關費用)。"</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"已從 <xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> 切換至<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"不明的網路類型"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" 網際網路連線狀況不佳。"</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"允許連線?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"「%1$s」應用程式要求連線至 WiFi 網路 %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"應用程式"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 Wi-Fi Direct 作業,這會關閉 Wi-Fi 用戶端/無線基地台作業。"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 Wi-Fi Direct。"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"輕觸即可查看設定"</string>
     <string name="accept" msgid="1645267259272829559">"接受"</string>
     <string name="decline" msgid="2112225451706137894">"拒絕"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀請函已傳送"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"連線邀請"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"寄件者:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件者:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN 碼:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"平板電腦與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Android TV 裝置與「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」連線期間將暫時中斷 Wi-Fi 連線"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"手機與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 連線期間將暫時中斷 Wi-Fi 連線"</string>
     <string name="select_character" msgid="3365550120617701745">"插入字元"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;&lt;/b&gt;「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在傳送大量簡訊。你要允許這個應用程式繼續傳送簡訊嗎?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"節約耗電量模式會關閉或限制背景活動、部分視覺效果,以及其他耗電量高的功能,藉此延長電池續航力。"<annotation id="url">"瞭解詳情"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"節約耗電量模式會關閉或限制背景活動、部分視覺效果,以及其他耗電量高的功能,藉此延長電池續航力。"</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 45bda9e..2ecc835 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1244,30 +1244,6 @@
     <string name="ringtone_picker_title_alarm" msgid="6473325356070549702">"Imisindo ye-alamu"</string>
     <string name="ringtone_picker_title_notification" msgid="4837740874822788802">"Imisindo yezaziso"</string>
     <string name="ringtone_unknown" msgid="3914515995813061520">"Akwaziwa"</string>
-    <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
-      <item quantity="one">Amanethiwekhi we-Wi-Fi ayatholakala</item>
-      <item quantity="other">Amanethiwekhi we-Wi-Fi ayatholakala</item>
-    </plurals>
-    <plurals name="wifi_available_detailed" formatted="false" msgid="1140699367193975606">
-      <item quantity="one">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
-      <item quantity="other">Vula amanethiwekhi we-Wi-Fi atholakalayo</item>
-    </plurals>
-    <string name="wifi_available_title" msgid="3817100557900599505">"Xhuma kunethiwekhi evulekile ye-Wi‑Fi"</string>
-    <string name="wifi_available_title_connecting" msgid="1139126673968899002">"Ixhumeka kunethiwekhi ye-Wi-Fi"</string>
-    <string name="wifi_available_title_connected" msgid="7542672851522241548">"Kuxhumeke kunethiwekhi ye-Wi‑Fi"</string>
-    <string name="wifi_available_title_failed_to_connect" msgid="6861772233582618132">"Ayikwazanga ukuxhumeka kunethiwekhi ye-Wi-Fi"</string>
-    <string name="wifi_available_content_failed_to_connect" msgid="3377406637062802645">"Thepha ukuze ubone onke amanethiwekhi"</string>
-    <string name="wifi_available_action_connect" msgid="2635699628459488788">"Xhuma"</string>
-    <string name="wifi_available_action_all_networks" msgid="4368435796357931006">"Onke amanethiwekhi"</string>
-    <string name="wifi_suggestion_title" msgid="6396033039578436801">"Vumela amanethiwekhi e-Wi-Fi aphakanyisiwe?"</string>
-    <string name="wifi_suggestion_content" msgid="5603992011371520746">"<xliff:g id="NAME">%s</xliff:g> amanethiwekhi aphakanyisiwe. Idivayisi ingaxhumeka ngokuzenzakalela."</string>
-    <string name="wifi_suggestion_action_allow_app" msgid="7978995387498669901">"Vumela"</string>
-    <string name="wifi_suggestion_action_disallow_app" msgid="6434097275967940372">"Cha ngiyabonga"</string>
-    <string name="wifi_wakeup_onboarding_title" msgid="228772560195634292">"I-Wi-Fi izovuleka ngokuzenzakalela"</string>
-    <string name="wifi_wakeup_onboarding_subtext" msgid="3989697580301186973">"Uma useduze kwenethiwekhi yekhwalithi ephezulu elondoloziwe"</string>
-    <string name="wifi_wakeup_onboarding_action_disable" msgid="838648204200836028">"Ungaphindi uvule"</string>
-    <string name="wifi_wakeup_enabled_title" msgid="6534603733173085309">"I-Wi‑Fi ivuleke ngokuzenzakalela"</string>
-    <string name="wifi_wakeup_enabled_content" msgid="189330154407990583">"Useduzane nenethiwekhi elondoloziwe: <xliff:g id="NETWORK_SSID">%1$s</xliff:g>"</string>
     <string name="wifi_available_sign_in" msgid="9157196203958866662">"Ngena ngemvume kunethiwekhi ye-Wi-Fi"</string>
     <string name="network_available_sign_in" msgid="1848877297365446605">"Ngena ngemvume kunethiwekhi"</string>
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
@@ -1280,9 +1256,6 @@
     <string name="captive_portal_logged_in_detailed" msgid="8489345381637456021">"Kuxhunyiwe"</string>
     <string name="network_partial_connectivity" msgid="7774883385494762741">"I-<xliff:g id="NETWORK_SSID">%1$s</xliff:g> inokuxhumeka okukhawulelwe"</string>
     <string name="network_partial_connectivity_detailed" msgid="1959697814165325217">"Thepha ukuze uxhume noma kunjalo"</string>
-    <string name="wifi_softap_config_change" msgid="8475911871165857607">"Ushintsho kuzilungiselelo zakho ze-hotspot"</string>
-    <string name="wifi_softap_config_change_summary" msgid="7601233252456548891">"Ibhendi yakho ye-hotspot ishintshile."</string>
-    <string name="wifi_softap_config_change_detailed" msgid="8022936822860678033">"Le divayisi ayisekeli okuncamelayo kwe-5GHz kuphela. Kunalokho, le divayisi izosebenzisa ibhendi ye-5GHz uma itholakala."</string>
     <string name="network_switch_metered" msgid="4671730921726992671">"Kushintshelwe ku-<xliff:g id="NETWORK_TYPE">%1$s</xliff:g>"</string>
     <string name="network_switch_metered_detail" msgid="775163331794506615">"Idivayisi isebenzisa i-<xliff:g id="NEW_NETWORK">%1$s</xliff:g> uma i-<xliff:g id="PREVIOUS_NETWORK">%2$s</xliff:g> inganakho ukufinyelela kwe-inthanethi. Kungasebenza izindleko."</string>
     <string name="network_switch_metered_toast" msgid="5779283181685974304">"Kushintshelewe kusuka ku-<xliff:g id="PREVIOUS_NETWORK">%1$s</xliff:g> kuya ku-<xliff:g id="NEW_NETWORK">%2$s</xliff:g>"</string>
@@ -1294,27 +1267,8 @@
     <item msgid="8257233890381651999">"I-VPN"</item>
   </string-array>
     <string name="network_switch_type_name_unknown" msgid="4552612897806660656">"uhlobo olungaziwa lwenethiwekhi"</string>
-    <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
-    <string name="wifi_watchdog_network_disabled_detailed" msgid="4917472096696322767">" inoxhumano oluphansi lwe-inthanethi."</string>
-    <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Vumela ukuxhumeka?"</string>
-    <string name="wifi_connect_alert_message" msgid="6451273376815958922">"Uhlelo lokusebenza %1$s lungathanda ukuxhuma kunethiwekhi ye-Wifi %2$s"</string>
-    <string name="wifi_connect_default_application" msgid="7143109390475484319">"Uhlelo lokusebenza"</string>
-    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-Wi-Fi Eqondile"</string>
-    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-Wi-Fi Okuqondile. Lokhu kuzocima ikhasimende le-Wi-Fi/Ukusebenza okwe-hotspot"</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Yehlulekile ukuqala i-Wi-Fi Ngqo"</string>
-    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Thepha ukuze uthole izilungiselelo"</string>
     <string name="accept" msgid="1645267259272829559">"Yamukela"</string>
     <string name="decline" msgid="2112225451706137894">"Nqaba"</string>
-    <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Isimemo sithunyelwe"</string>
-    <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Isimemo kuya kokuqukethwe"</string>
-    <string name="wifi_p2p_from_message" msgid="570389174731951769">"Kusuka:"</string>
-    <string name="wifi_p2p_to_message" msgid="248968974522044099">"Ku:"</string>
-    <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string>
-    <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tablet" msgid="8012981257742232475">"Ithebulethi izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="tv" msgid="5046724574683503190">"Idivayisi yakho ye-Android TV izonqamula okwesikhashana kusuka ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
-    <string name="wifi_p2p_frequency_conflict_message" product="default" msgid="7363907213787469151">"Ifoni izonqamuka okwesikhashana ku-Wi-Fi ngenkathi ixhumeke ku-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
     <string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string>
     <string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"I-&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; ithumela inombolo enkulu yemilayezo ye-SMS. Ufuna ukuvumela lolu hlelo lokusebenza ukuqhubeka ukuthumela imilayezo?"</string>
@@ -1817,8 +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>
-    <string name="battery_saver_description_with_learn_more" msgid="2108984221113106294">"Isilondolozi sebhethri sivala noma sikhawulela umsebenzi ongemuva, eminye imithelela ebonakalayo kanye nezinye izici zamandla aphezulu ukuze kunwetshwe impilo yebhethri. "<annotation id="url">"Funda kabanzi"</annotation></string>
-    <string name="battery_saver_description" msgid="6413346684861241431">"Isilondolozi sebhethri sivala noma sikhawulela umsebenzi ongemuva, eminye imithelela ebonakalayo kanye nezinye izici zamandla aphezulu ukuze kunwetshwe impilo yebhethri."</string>
+    <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>
@@ -2051,4 +2005,23 @@
     </plurals>
     <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 acaaeec..642dc92 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -359,13 +359,13 @@
              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" />
-        <!-- Flag indicating whether this is a translucent window. If this attribute is unset (but
-             not if set to false), the window might still be considered translucent, if
-             windowSwipeToDismiss is set to true. -->
+        <!-- Flag indicating whether this is a translucent window. -->
         <attr name="windowIsTranslucent" format="boolean" />
         <!-- Flag indicating that this window's background should be the
              user's current wallpaper.  Corresponds
@@ -492,7 +492,9 @@
         <!-- Flag to indicate that a window can be swiped away to be dismissed.
              Corresponds to {@link android.view.Window#FEATURE_SWIPE_TO_DISMISS}. It will also
              dynamically change translucency of the window, if the windowIsTranslucent is not set.
-             If windowIsTranslucent is set (to either true or false) it will obey that setting. -->
+             If windowIsTranslucent is set (to either true or false) it will obey that setting.
+             @deprecated Swipe-to-dismiss isn't functional anymore.
+             -->
         <attr name="windowSwipeToDismiss" format="boolean" />
 
         <!-- Flag indicating whether this window requests that content changes be performed
@@ -1961,7 +1963,6 @@
         <attr name="windowCloseOnTouchOutside" />
         <attr name="windowTranslucentStatus" />
         <attr name="windowTranslucentNavigation" />
-        <attr name="windowSwipeToDismiss" />
         <attr name="windowContentTransitions" />
         <attr name="windowActivityTransitions" />
         <attr name="windowContentTransitionManager" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e425ef0..e6f038a 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1873,6 +1873,10 @@
     <bool name="config_showDefaultEmergency">false</bool>
     <!-- Whether the default home settings should be shown. -->
     <bool name="config_showDefaultHome">true</bool>
+    <!-- The name of the package that will hold the call redirection role by default. -->
+    <string name="config_defaultCallRedirection" translatable="false"></string>
+    <!-- The name of the package that will hold the call screening role by default. -->
+    <string name="config_defaultCallScreening" translatable="false"></string>
 
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
@@ -2656,6 +2660,9 @@
     <!-- The amount to scale fullscreen snapshots for Overview and snapshot starting windows. -->
     <item name="config_fullTaskSnapshotScale" format="float" type="dimen">1.0</item>
 
+    <!-- Feature flag to store TaskSnapshot in 16 bit pixel format to save memory. -->
+    <bool name="config_use16BitTaskSnapshotPixelFormat">false</bool>
+
     <!-- Determines whether recent tasks are provided to the user. Default device has recents
          property. If this is false, then the following recents config flags are ignored. -->
     <bool name="config_hasRecents">true</bool>
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
index 8737df8..64483f1 100644
--- a/core/res/res/values/config_material.xml
+++ b/core/res/res/values/config_material.xml
@@ -29,12 +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 windowSwipeToDismiss should be on by default. -->
-    <bool name="config_windowSwipeToDismiss">false</bool>
-
     <!-- True if preference fragment should clip to padding. -->
     <bool name="config_preferenceFragmentClipToPadding">true</bool>
 
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 2b0c86b..b52f535 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -179,11 +179,11 @@
   <!-- Action used to manually trigger an autofill request -->
   <item type="id" name="autofill" />
 
-    <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_TOOLTIP}. -->
-    <item type="id" name="accessibilityActionShowTooltip" />
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_SHOW_TOOLTIP}. -->
+  <item type="id" name="accessibilityActionShowTooltip" />
 
-    <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. -->
-    <item type="id" name="accessibilityActionHideTooltip" />
+  <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_HIDE_TOOLTIP}. -->
+  <item type="id" name="accessibilityActionHideTooltip" />
 
   <!-- A tag used to save the view added to a transition overlay -->
   <item type="id" name="transition_overlay_view_tag" />
@@ -193,4 +193,31 @@
 
   <!-- A tag used to save the index where the custom view is stored -->
   <item type="id" name="notification_custom_view_index_tag" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK}. -->
+  <item type="id" name="accessibilitySystemActionBack" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_HOME}. -->
+  <item type="id" name="accessibilitySystemActionHome" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_RECENTS}. -->
+  <item type="id" name="accessibilitySystemActionRecents" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_NOTIFICATIONS}. -->
+  <item type="id" name="accessibilitySystemActionNotifications" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_QUICK_SETTINGS}. -->
+  <item type="id" name="accessibilitySystemActionQuickSettings" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_POWER_DIALOG}. -->
+  <item type="id" name="accessibilitySystemActionPowerDialog" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN}. -->
+  <item type="id" name="accessibilitySystemActionToggleSplitScreen" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_LOCK_SCREEN}. -->
+  <item type="id" name="accessibilitySystemActionLockScreen" />
+
+  <!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TAKE_SCREENSHOT}. -->
+  <item type="id" name="accessibilitySystemActionTakeScreenshot" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 9b89eab..cde95aa 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3022,6 +3022,10 @@
       <public name="notification_channel_network_alerts" />
       <!-- @hide @SystemApi -->
       <public name="notification_channel_network_available" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultCallRedirection" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultCallScreening" />
     </public-group>
 
     <public-group type="bool" first-id="0x01110005">
@@ -3033,6 +3037,17 @@
     <public-group type="color" first-id="0x0106001d">
     </public-group>
 
+    <public-group type="id" first-id="0x0102004b">
+      <public name="accessibilitySystemActionBack" />
+      <public name="accessibilitySystemActionHome" />
+      <public name="accessibilitySystemActionRecents" />
+      <public name="accessibilitySystemActionNotifications" />
+      <public name="accessibilitySystemActionQuickSettings" />
+      <public name="accessibilitySystemActionPowerDialog" />
+      <public name="accessibilitySystemActionToggleSplitScreen" />
+      <public name="accessibilitySystemActionLockScreen" />
+      <public name="accessibilitySystemActionTakeScreenshot" />
+    </public-group>
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f8eb90b..42e62d7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -720,8 +720,8 @@
     <!-- Message shown to the user when the apps requests permission to use the location while app is in foreground and background. If ever possible this should stay below 80 characters (assuming the parameters takes 20 characters). Don't abbreviate until the message reaches 120 characters though. [CHAR LIMIT=120] -->
     <string name="permgroupbackgroundrequest_location">Allow
         &lt;b><xliff:g id="app_name" example="Gmail">%1$s</xliff:g>&lt;/b> to access this device\u2019s location &lt;b>all the time&lt;/b>?</string>
-    <!-- Subtitle of the message shown to the user when the apps requests permission to use the location while app is in foreground and background [CHAR LIMIT=150] -->
-    <string name="permgroupbackgroundrequestdetail_location">App currently can access location only while you\u2019re using the app</string>
+    <!-- Subtitle of the message shown to the user when the apps requests permission to use the location while app is in foreground and background. Try to keep the link annotation at the end of the string [CHAR LIMIT=150] -->
+    <string name="permgroupbackgroundrequestdetail_location">This app may want to access your location all the time, even when you\u2019re not using the app. Allow in <annotation id="link">settings</annotation>.</string>
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permgrouplab_calendar">Calendar</string>
@@ -5339,4 +5339,24 @@
 
     <!-- Prompt for the USB device resolver dialog with warning text for USB device dialogs.  [CHAR LIMIT=200] -->
     <string name="usb_device_resolve_prompt_warn">This app has not been granted record permission but could capture audio through this USB device.</string>
+
+    <!-- Accessibility system actions -->
+    <!-- Label for Home action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_home_label">Home</string>
+    <!-- Label for Back action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_back_label">Back</string>
+    <!-- Label for showing recent apps action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_recents_label">Recent Apps</string>
+    <!-- Label for opening notifications action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_notifications_label">Notifications</string>
+    <!-- Label for opening quick settings action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_quick_settings_label">Quick Settings</string>
+    <!-- Label for opening power dialog action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_power_dialog_label">Power Dialog</string>
+    <!-- Label for toggle split screen action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_toggle_split_screen_label">Toggle Split Screen</string>
+    <!-- Label for lock screen action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_lock_screen_label">Lock Screen</string>
+    <!-- Label for taking screenshot action [CHAR LIMIT=NONE] -->
+    <string name="accessibility_system_action_screenshot_label">Screenshot</string>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index a2df060..e56bbf6 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -356,6 +356,7 @@
   <java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
   <java-symbol type="bool" name="config_disableUsbPermissionDialogs"/>
   <java-symbol type="dimen" name="config_fullTaskSnapshotScale" />
+  <java-symbol type="bool" name="config_use16BitTaskSnapshotPixelFormat" />
   <java-symbol type="bool" name="config_lowRamTaskSnapshotsAndRecents" />
   <java-symbol type="bool" name="config_hasRecents" />
   <java-symbol type="string" name="config_recentsComponentName" />
@@ -1742,7 +1743,6 @@
   <java-symbol type="layout" name="screen_progress" />
   <java-symbol type="layout" name="screen_simple" />
   <java-symbol type="layout" name="screen_simple_overlay_action_mode" />
-  <java-symbol type="layout" name="screen_swipe_dismiss" />
   <java-symbol type="layout" name="screen_title" />
   <java-symbol type="layout" name="screen_title_icons" />
   <java-symbol type="string" name="system_ui_date_pattern" />
@@ -3753,4 +3753,14 @@
 
   <java-symbol type="string" name="usb_device_resolve_prompt_warn" />
 
+  <!-- For Accessibility system actions -->
+  <java-symbol type="string" name="accessibility_system_action_back_label" />
+  <java-symbol type="string" name="accessibility_system_action_home_label" />
+  <java-symbol type="string" name="accessibility_system_action_lock_screen_label" />
+  <java-symbol type="string" name="accessibility_system_action_notifications_label" />
+  <java-symbol type="string" name="accessibility_system_action_power_dialog_label" />
+  <java-symbol type="string" name="accessibility_system_action_quick_settings_label" />
+  <java-symbol type="string" name="accessibility_system_action_recents_label" />
+  <java-symbol type="string" name="accessibility_system_action_screenshot_label" />
+  <java-symbol type="string" name="accessibility_system_action_toggle_split_screen_label" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index ce29389..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>
@@ -182,7 +181,6 @@
         <item name="windowSharedElementExitTransition">@transition/move</item>
         <item name="windowContentTransitions">false</item>
         <item name="windowActivityTransitions">true</item>
-        <item name="windowSwipeToDismiss">@bool/config_windowSwipeToDismiss</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
@@ -537,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>
@@ -557,7 +554,6 @@
         <item name="windowSharedElementExitTransition">@transition/move</item>
         <item name="windowContentTransitions">false</item>
         <item name="windowActivityTransitions">true</item>
-        <item name="windowSwipeToDismiss">@bool/config_windowSwipeToDismiss</item>
 
         <!-- Dialog attributes -->
         <item name="dialogTheme">@style/ThemeOverlay.Material.Dialog</item>
@@ -965,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>
 
@@ -998,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/com.android.settings.xml b/data/etc/com.android.settings.xml
index 72be9f5..1882c3f 100644
--- a/data/etc/com.android.settings.xml
+++ b/data/etc/com.android.settings.xml
@@ -34,6 +34,7 @@
         <permission name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE" />
         <permission name="android.permission.MASTER_CLEAR"/>
         <permission name="android.permission.MEDIA_CONTENT_CONTROL"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
         <permission name="android.permission.MODIFY_PHONE_STATE"/>
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 77b0dba..d2ce4e0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -95,6 +95,9 @@
     <privapp-permissions package="com.android.mtp">
         <permission name="android.permission.ACCESS_MTP"/>
         <permission name="android.permission.MANAGE_USB"/>
+        <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+        <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
     </privapp-permissions>
 
     <privapp-permissions package="com.android.musicfx">
@@ -207,6 +210,7 @@
         <permission name="android.permission.USE_RESERVED_DISK"/>
         <permission name="android.permission.WRITE_MEDIA_STORAGE"/>
         <permission name="android.permission.WATCH_APPOPS"/>
+        <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
         <permission name="android.permission.UPDATE_DEVICE_STATS"/>
     </privapp-permissions>
 
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 5b9b703..753f8a0 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1093,6 +1093,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "200829729": {
+      "message": "ScreenRotationAnimation onAnimationEnd",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
     "221540118": {
       "message": "mUserActivityTimeout set to %d",
       "level": "DEBUG",
@@ -1159,6 +1165,12 @@
       "group": "WM_DEBUG_APP_TRANSITIONS",
       "at": "com\/android\/server\/wm\/AppTransitionController.java"
     },
+    "292555239": {
+      "message": "ScreenRotation sill animating: mDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ORIENTATION",
+      "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+    },
     "292904800": {
       "message": "Deferring rotation, animation in progress.",
       "level": "VERBOSE",
@@ -1345,12 +1357,6 @@
       "group": "WM_SHOW_TRANSACTIONS",
       "at": "com\/android\/server\/wm\/Session.java"
     },
-    "609651209": {
-      "message": "addChild: %s at top.",
-      "level": "VERBOSE",
-      "group": "WM_DEBUG_ADD_REMOVE",
-      "at": "com\/android\/server\/wm\/TaskRecord.java"
-    },
     "620368427": {
       "message": "******* TELLING SURFACE FLINGER WE ARE BOOTED!",
       "level": "INFO",
@@ -1669,6 +1675,12 @@
       "group": "WM_DEBUG_ORIENTATION",
       "at": "com\/android\/server\/wm\/WindowState.java"
     },
+    "1330804250": {
+      "message": "addChild: %s at top.",
+      "level": "VERBOSE",
+      "group": "WM_DEBUG_ADD_REMOVE",
+      "at": "com\/android\/server\/wm\/Task.java"
+    },
     "1331177619": {
       "message": "Attempted to add a toast window with unknown token %s.  Aborting.",
       "level": "WARN",
diff --git a/data/sounds/AudioPackage11.mk b/data/sounds/AudioPackage11.mk
index 99dfd0a..2392b33 100644
--- a/data/sounds/AudioPackage11.mk
+++ b/data/sounds/AudioPackage11.mk
@@ -32,7 +32,7 @@
 	$(LOCAL_PATH)/effects/ogg/Lock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Lock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Unlock_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Unlock.ogg \
 	$(LOCAL_PATH)/effects/ogg/Trusted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Trusted.ogg \
-	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \.
+	$(LOCAL_PATH)/effects/ogg/ChargingStarted.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/ChargingStarted.ogg \
 	$(LOCAL_PATH)/effects/ogg/InCallNotification.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/InCallNotification.ogg \
 	$(LOCAL_PATH)/effects/material/ogg/WirelessChargingStarted_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/WirelessChargingStarted.ogg \
 	$(LOCAL_PATH)/notifications/ogg/Adara.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/notifications/Adara.ogg \
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index 5648b85..a815f20 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -2095,9 +2095,11 @@
 
     /**
      * Draw the text, with origin at (x,y), using the specified paint, along the specified path. The
-     * paint's Align setting determins where along the path to start the text.
+     * paint's Align setting determines where along the path to start the text.
      *
      * @param text The text to be drawn
+     * @param index The starting index within the text to be drawn
+     * @param count Starting from index, the number of characters to draw
      * @param path The path the text should follow for its baseline
      * @param hOffset The distance along the path to add to the text's starting position
      * @param vOffset The distance above(-) or below(+) the path to position the text
@@ -2110,7 +2112,7 @@
 
     /**
      * Draw the text, with origin at (x,y), using the specified paint, along the specified path. The
-     * paint's Align setting determins where along the path to start the text.
+     * paint's Align setting determines where along the path to start the text.
      *
      * @param text The text to be drawn
      * @param path The path the text should follow for its baseline
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 3658f89..c2e3c64 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -92,11 +92,17 @@
      * @see #getType
      */
     public static final int TYPE_ADAPTIVE_BITMAP = 5;
+    /**
+     * An icon that was created using {@link Icon#createWithAdaptiveBitmapContentUri}.
+     * @see #getType
+     */
+    public static final int TYPE_URI_ADAPTIVE_BITMAP = 6;
 
     /**
      * @hide
      */
-    @IntDef({TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP})
+    @IntDef({TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP,
+            TYPE_URI_ADAPTIVE_BITMAP})
     public @interface IconType {
     }
 
@@ -113,12 +119,14 @@
     // based on the value of mType.
 
     // TYPE_BITMAP: Bitmap
+    // TYPE_ADAPTIVE_BITMAP: Bitmap
     // TYPE_RESOURCE: Resources
     // TYPE_DATA: DataBytes
     private Object          mObj1;
 
     // TYPE_RESOURCE: package name
     // TYPE_URI: uri string
+    // TYPE_URI_ADAPTIVE_BITMAP: uri string
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private String          mString1;
 
@@ -141,7 +149,8 @@
     }
 
     /**
-     * @return The {@link android.graphics.Bitmap} held by this {@link #TYPE_BITMAP} Icon.
+     * @return The {@link android.graphics.Bitmap} held by this {@link #TYPE_BITMAP} or
+     * {@link #TYPE_ADAPTIVE_BITMAP} Icon.
      * @hide
      */
     @UnsupportedAppUsage
@@ -243,11 +252,12 @@
     }
 
     /**
-     * @return The URI (as a String) for this {@link #TYPE_URI} Icon.
+     * @return The URI (as a String) for this {@link #TYPE_URI} or {@link #TYPE_URI_ADAPTIVE_BITMAP}
+     * Icon.
      * @hide
      */
     public String getUriString() {
-        if (mType != TYPE_URI) {
+        if (mType != TYPE_URI && mType != TYPE_URI_ADAPTIVE_BITMAP) {
             throw new IllegalStateException("called getUriString() on " + this);
         }
         return mString1;
@@ -256,7 +266,7 @@
     /**
      * Gets the uri used to create this icon.
      * <p>
-     * Only valid for icons of type {@link #TYPE_URI}.
+     * Only valid for icons of type {@link #TYPE_URI} and {@link #TYPE_URI_ADAPTIVE_BITMAP}.
      * Note: This uri may not be available in the future, and it is
      * up to the caller to ensure safety if this uri is re-used and/or persisted.
      */
@@ -272,6 +282,7 @@
             case TYPE_DATA: return "DATA";
             case TYPE_RESOURCE: return "RESOURCE";
             case TYPE_URI: return "URI";
+            case TYPE_URI_ADAPTIVE_BITMAP: return "URI_MASKABLE";
             default: return "UNKNOWN";
         }
     }
@@ -380,28 +391,39 @@
                     BitmapFactory.decodeByteArray(getDataBytes(), getDataOffset(), getDataLength())
                 );
             case TYPE_URI:
-                final Uri uri = getUri();
-                final String scheme = uri.getScheme();
-                InputStream is = null;
-                if (ContentResolver.SCHEME_CONTENT.equals(scheme)
-                        || ContentResolver.SCHEME_FILE.equals(scheme)) {
-                    try {
-                        is = context.getContentResolver().openInputStream(uri);
-                    } catch (Exception e) {
-                        Log.w(TAG, "Unable to load image from URI: " + uri, e);
-                    }
-                } else {
-                    try {
-                        is = new FileInputStream(new File(mString1));
-                    } catch (FileNotFoundException e) {
-                        Log.w(TAG, "Unable to load image from path: " + uri, e);
-                    }
-                }
+                InputStream is = getUriInputStream(context);
                 if (is != null) {
                     return new BitmapDrawable(context.getResources(),
                             BitmapFactory.decodeStream(is));
                 }
                 break;
+            case TYPE_URI_ADAPTIVE_BITMAP:
+                is = getUriInputStream(context);
+                if (is != null) {
+                    return new AdaptiveIconDrawable(null, new BitmapDrawable(context.getResources(),
+                            BitmapFactory.decodeStream(is)));
+                }
+                break;
+        }
+        return null;
+    }
+
+    private InputStream getUriInputStream(Context context) {
+        final Uri uri = getUri();
+        final String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+                || ContentResolver.SCHEME_FILE.equals(scheme)) {
+            try {
+                return context.getContentResolver().openInputStream(uri);
+            } catch (Exception e) {
+                Log.w(TAG, "Unable to load image from URI: " + uri, e);
+            }
+        } else {
+            try {
+                return new FileInputStream(new File(mString1));
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Unable to load image from path: " + uri, e);
+            }
         }
         return null;
     }
@@ -475,6 +497,7 @@
                 dataStream.writeInt(getResId());
                 break;
             case TYPE_URI:
+            case TYPE_URI_ADAPTIVE_BITMAP:
                 dataStream.writeUTF(getUriString());
                 break;
         }
@@ -513,6 +536,9 @@
                 case TYPE_URI:
                     final String uriOrPath = inputStream.readUTF();
                     return createWithContentUri(uriOrPath);
+                case TYPE_URI_ADAPTIVE_BITMAP:
+                    final String uri = inputStream.readUTF();
+                    return createWithAdaptiveBitmapContentUri(uri);
             }
         }
         return null;
@@ -545,6 +571,7 @@
                 return getResId() == otherIcon.getResId()
                         && Objects.equals(getResPackage(), otherIcon.getResPackage());
             case TYPE_URI:
+            case TYPE_URI_ADAPTIVE_BITMAP:
                 return Objects.equals(getUriString(), otherIcon.getUriString());
         }
         return false;
@@ -665,12 +692,40 @@
         if (uri == null) {
             throw new IllegalArgumentException("Uri must not be null.");
         }
-        final Icon rep = new Icon(TYPE_URI);
-        rep.mString1 = uri.toString();
+        return createWithContentUri(uri.toString());
+    }
+
+    /**
+     * Create an Icon pointing to an image file specified by URI. Image file should follow the icon
+     * design guideline defined by {@link AdaptiveIconDrawable}.
+     *
+     * @param uri A uri referring to local content:// or file:// image data.
+     */
+    @NonNull
+    public static Icon createWithAdaptiveBitmapContentUri(@NonNull String uri) {
+        if (uri == null) {
+            throw new IllegalArgumentException("Uri must not be null.");
+        }
+        final Icon rep = new Icon(TYPE_URI_ADAPTIVE_BITMAP);
+        rep.mString1 = uri;
         return rep;
     }
 
     /**
+     * Create an Icon pointing to an image file specified by URI. Image file should follow the icon
+     * design guideline defined by {@link AdaptiveIconDrawable}.
+     *
+     * @param uri A uri referring to local content:// or file:// image data.
+     */
+    @NonNull
+    public static Icon createWithAdaptiveBitmapContentUri(@NonNull Uri uri) {
+        if (uri == null) {
+            throw new IllegalArgumentException("Uri must not be null.");
+        }
+        return createWithAdaptiveBitmapContentUri(uri.toString());
+    }
+
+    /**
      * Store a color to use whenever this Icon is drawn.
      *
      * @param tint a color, as in {@link Drawable#setTint(int)}
@@ -758,6 +813,7 @@
                 }
                 break;
             case TYPE_URI:
+            case TYPE_URI_ADAPTIVE_BITMAP:
                 sb.append(" uri=").append(getUriString());
                 break;
         }
@@ -809,6 +865,7 @@
                 mObj1 = a;
                 break;
             case TYPE_URI:
+            case TYPE_URI_ADAPTIVE_BITMAP:
                 final String uri = in.readString();
                 mString1 = uri;
                 break;
@@ -840,6 +897,7 @@
                 dest.writeBlob(getDataBytes(), getDataOffset(), getDataLength());
                 break;
             case TYPE_URI:
+            case TYPE_URI_ADAPTIVE_BITMAP:
                 dest.writeString(getUriString());
                 break;
         }
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 538319c..a7e17d1 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -55,8 +55,8 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
 
 import javax.security.auth.x500.X500Principal;
 
@@ -811,27 +811,22 @@
             throw new NullPointerException("context == null");
         }
         ensureNotOnMainThread(context);
-        final BlockingQueue<IKeyChainService> q = new LinkedBlockingQueue<IKeyChainService>(1);
+        final CountDownLatch countDownLatch = new CountDownLatch(1);
+        final AtomicReference<IKeyChainService> keyChainService = new AtomicReference<>();
         ServiceConnection keyChainServiceConnection = new ServiceConnection() {
             volatile boolean mConnectedAtLeastOnce = false;
             @Override public void onServiceConnected(ComponentName name, IBinder service) {
                 if (!mConnectedAtLeastOnce) {
                     mConnectedAtLeastOnce = true;
-                    try {
-                        q.put(IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
-                    } catch (InterruptedException e) {
-                        // will never happen, since the queue starts with one available slot
-                    }
+                    keyChainService.set(
+                            IKeyChainService.Stub.asInterface(Binder.allowBlocking(service)));
+                    countDownLatch.countDown();
                 }
             }
             @Override public void onBindingDied(ComponentName name) {
                 if (!mConnectedAtLeastOnce) {
                     mConnectedAtLeastOnce = true;
-                    try {
-                        q.put(null);
-                    } catch (InterruptedException e) {
-                        // will never happen, since the queue starts with one available slot
-                    }
+                    countDownLatch.countDown();
                 }
             }
             @Override public void onServiceDisconnected(ComponentName name) {}
@@ -843,7 +838,8 @@
                 intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
             throw new AssertionError("could not bind to KeyChainService");
         }
-        IKeyChainService service = q.take();
+        countDownLatch.await();
+        IKeyChainService service = keyChainService.get();
         if (service != null) {
             return new KeyChainConnection(context, keyChainServiceConnection, service);
         } else {
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 bd6ce7e..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;
@@ -1256,6 +1261,7 @@
          *
          * Sets whether to include a temporary unique ID field in the attestation certificate.
          */
+        @UnsupportedAppUsage
         @TestApi
         @NonNull
         public Builder setUniqueIdIncluded(boolean uniqueIdIncluded) {
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 16dbbf6..18934fd 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -43,20 +43,22 @@
 ApkAssets::ApkAssets(ZipArchiveHandle unmanaged_handle,
                      const std::string& path,
                      time_t last_mod_time,
-                     bool for_loader)
+                     package_property_t property_flags)
     : zip_handle_(unmanaged_handle, ::CloseArchive), path_(path), last_mod_time_(last_mod_time),
-      for_loader_(for_loader) {
+      property_flags_(property_flags) {
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::Load(const std::string& path, bool system,
                                                  bool for_loader) {
-  return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, false /*load_as_shared_library*/,
-                  for_loader);
+  package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
+                             (for_loader ? PROPERTY_LOADER : 0U);
+  return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadAsSharedLibrary(const std::string& path,
                                                                 bool system) {
-  return LoadImpl({} /*fd*/, path, nullptr, nullptr, system, true /*load_as_shared_library*/);
+  package_property_t flags = PROPERTY_DYNAMIC | (system ? PROPERTY_SYSTEM : 0U);
+  return LoadImpl({} /*fd*/, path, nullptr, nullptr, flags);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap_path,
@@ -74,27 +76,33 @@
     LOG(ERROR) << "failed to load IDMAP " << idmap_path;
     return {};
   }
-  return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(), std::move(idmap_asset),
-                  std::move(loaded_idmap), system, true /*load_as_shared_library*/);
+
+  return LoadImpl({} /*fd*/, loaded_idmap->OverlayApkPath(),
+                  std::move(idmap_asset),
+                  std::move(loaded_idmap),
+                  PROPERTY_OVERLAY | (system ? PROPERTY_SYSTEM : 0U));
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadFromFd(unique_fd fd,
                                                        const std::string& friendly_name,
                                                        bool system, bool force_shared_lib,
                                                        bool for_loader) {
+  package_property_t flags = (system ? PROPERTY_SYSTEM : 0U) |
+                             (force_shared_lib ? PROPERTY_DYNAMIC : 0U) |
+                             (for_loader ? PROPERTY_LOADER : 0U);
   return LoadImpl(std::move(fd), friendly_name, nullptr /*idmap_asset*/, nullptr /*loaded_idmap*/,
-                  system, force_shared_lib, for_loader);
+                  flags);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(const std::string& path,
                                                      bool for_loader) {
-  return LoadArscImpl({} /*fd*/, path, for_loader);
+  return LoadArscImpl({} /*fd*/, path, for_loader ? PROPERTY_LOADER : 0U);
 }
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadArsc(unique_fd fd,
                                                      const std::string& friendly_name,
                                                      bool for_loader) {
-  return LoadArscImpl(std::move(fd), friendly_name, for_loader);
+  return LoadArscImpl(std::move(fd), friendly_name, for_loader ? PROPERTY_LOADER : 0U);
 }
 
 std::unique_ptr<Asset> ApkAssets::CreateAssetFromFile(const std::string& path) {
@@ -120,8 +128,7 @@
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
     unique_fd fd, const std::string& path, std::unique_ptr<Asset> idmap_asset,
-    std::unique_ptr<const LoadedIdmap> loaded_idmap, bool system, bool load_as_shared_library,
-    bool for_loader) {
+    std::unique_ptr<const LoadedIdmap> loaded_idmap, package_property_t property_flags) {
   ::ZipArchiveHandle unmanaged_handle;
   int32_t result;
   if (fd >= 0) {
@@ -141,7 +148,7 @@
 
   // Wrap the handle in a unique_ptr so it gets automatically closed.
   std::unique_ptr<ApkAssets>
-      loaded_apk(new ApkAssets(unmanaged_handle, path, last_mod_time, for_loader));
+      loaded_apk(new ApkAssets(unmanaged_handle, path, last_mod_time, property_flags));
 
   // Find the resource table.
   ::ZipEntry entry;
@@ -170,9 +177,8 @@
   const StringPiece data(
       reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
       loaded_apk->resources_asset_->getLength());
-  loaded_apk->loaded_arsc_ =
-      LoadedArsc::Load(data, loaded_apk->loaded_idmap_.get(), system, load_as_shared_library,
-                       for_loader);
+  loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, loaded_apk->loaded_idmap_.get(),
+                                              property_flags);
   if (loaded_apk->loaded_arsc_ == nullptr) {
     LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
     return {};
@@ -184,7 +190,7 @@
 
 std::unique_ptr<const ApkAssets> ApkAssets::LoadArscImpl(unique_fd fd,
                                                          const std::string& path,
-                                                         bool for_loader) {
+                                                         package_property_t property_flags) {
   std::unique_ptr<Asset> resources_asset;
 
   if (fd >= 0) {
@@ -201,13 +207,14 @@
 
   time_t last_mod_time = getFileModDate(path.c_str());
 
-  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets(nullptr, path, last_mod_time, for_loader));
+  std::unique_ptr<ApkAssets> loaded_apk(
+      new ApkAssets(nullptr, path, last_mod_time, property_flags));
   loaded_apk->resources_asset_ = std::move(resources_asset);
 
   const StringPiece data(
       reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
       loaded_apk->resources_asset_->getLength());
-  loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, false, false, for_loader);
+  loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, property_flags);
   if (loaded_apk->loaded_arsc_ == nullptr) {
     LOG(ERROR) << "Failed to load '" << kResourcesArsc << path;
     return {};
@@ -320,8 +327,8 @@
 }
 
 bool ApkAssets::IsUpToDate() const {
-  // Loaders are invalidated by the app, not the system, so assume up to date
-  if (for_loader_) {
+  if (IsLoader()) {
+    // Loaders are invalidated by the app, not the system, so assume up to date.
     return true;
   }
 
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 2b69c92..773353d 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -44,8 +44,8 @@
 }
 
 OverlayStringPool::OverlayStringPool(const LoadedIdmap* loaded_idmap)
-                                     : data_header_(loaded_idmap->data_header_),
-                                       idmap_string_pool_(loaded_idmap->string_pool_.get()) { };
+    : data_header_(loaded_idmap->data_header_),
+      idmap_string_pool_(loaded_idmap->string_pool_.get()) { };
 
 OverlayStringPool::~OverlayStringPool() {
   uninit();
@@ -188,11 +188,12 @@
                          const Idmap_data_header* data_header,
                          const Idmap_target_entry* target_entries,
                          const Idmap_overlay_entry* overlay_entries,
-                         ResStringPool* string_pool) : header_(header),
-                                                       data_header_(data_header),
-                                                       target_entries_(target_entries),
-                                                       overlay_entries_(overlay_entries),
-                                                       string_pool_(string_pool) {
+                         ResStringPool* string_pool)
+     : header_(header),
+       data_header_(data_header),
+       target_entries_(target_entries),
+       overlay_entries_(overlay_entries),
+       string_pool_(string_pool) {
 
   size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path),
                           arraysize(header_->overlay_path));
@@ -264,7 +265,7 @@
     }
   }
 
-   // Can't use make_unique because LoadedImpl constructor is private.
+  // Can't use make_unique because LoadedIdmap constructor is private.
   std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>(
       new LoadedIdmap(header, data_header, target_entries, overlay_entries,
                       idmap_string_pool.release()));
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index c896241..e35c024 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -397,9 +397,7 @@
 }
 
 std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk,
-                                                         bool system,
-                                                         bool load_as_shared_library,
-                                                         bool for_loader) {
+                                                         package_property_t property_flags) {
   ATRACE_NAME("LoadedPackage::Load");
   std::unique_ptr<LoadedPackage> loaded_package(new LoadedPackage());
 
@@ -413,17 +411,24 @@
     return {};
   }
 
-  loaded_package->system_ = system;
+  if ((property_flags & PROPERTY_SYSTEM) != 0) {
+    loaded_package->property_flags_ |= PROPERTY_SYSTEM;
+  }
+
+  if ((property_flags & PROPERTY_LOADER) != 0) {
+    loaded_package->property_flags_ |= PROPERTY_LOADER;
+  }
+
+  if ((property_flags & PROPERTY_OVERLAY) != 0) {
+    // Overlay resources must have an exclusive resource id space for referencing internal
+    // resources.
+    loaded_package->property_flags_ |= PROPERTY_OVERLAY | PROPERTY_DYNAMIC;
+  }
 
   loaded_package->package_id_ = dtohl(header->id);
   if (loaded_package->package_id_ == 0 ||
-      (loaded_package->package_id_ == kAppPackageId && load_as_shared_library)) {
-    // Package ID of 0 means this is a shared library.
-    loaded_package->dynamic_ = true;
-  }
-
-  if (for_loader) {
-    loaded_package->custom_loader_ = true;
+      (loaded_package->package_id_ == kAppPackageId && (property_flags & PROPERTY_DYNAMIC) != 0)) {
+    loaded_package->property_flags_ |= PROPERTY_DYNAMIC;
   }
 
   if (header->header.headerSize >= sizeof(ResTable_package)) {
@@ -677,7 +682,7 @@
 }
 
 bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
-                           bool load_as_shared_library, bool for_loader) {
+                           package_property_t property_flags) {
   const ResTable_header* header = chunk.header<ResTable_header>();
   if (header == nullptr) {
     LOG(ERROR) << "RES_TABLE_TYPE too small.";
@@ -720,7 +725,7 @@
         packages_seen++;
 
         std::unique_ptr<const LoadedPackage> loaded_package =
-            LoadedPackage::Load(child_chunk, system_, load_as_shared_library, for_loader);
+            LoadedPackage::Load(child_chunk, property_flags);
         if (!loaded_package) {
           return false;
         }
@@ -744,24 +749,18 @@
 
 std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
                                                    const LoadedIdmap* loaded_idmap,
-                                                   bool system,
-                                                   bool load_as_shared_library,
-                                                   bool for_loader) {
+                                                   package_property_t property_flags) {
   ATRACE_NAME("LoadedArsc::Load");
 
   // Not using make_unique because the constructor is private.
   std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
-  loaded_arsc->system_ = system;
 
   ChunkIterator iter(data.data(), data.size());
   while (iter.HasNext()) {
     const Chunk chunk = iter.Next();
     switch (chunk.type()) {
       case RES_TABLE_TYPE:
-        if (!loaded_arsc->LoadTable(chunk,
-                                    loaded_idmap,
-                                    load_as_shared_library,
-                                    for_loader)) {
+        if (!loaded_arsc->LoadTable(chunk, loaded_idmap, property_flags)) {
           return {};
         }
         break;
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
index 2047287..af802b0 100644
--- a/libs/androidfw/include/androidfw/ApkAssets.h
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -76,10 +76,10 @@
   // Takes ownership of the file descriptor.
   static std::unique_ptr<const ApkAssets> LoadArsc(base::unique_fd fd,
                                                    const std::string& friendly_name,
-                                                   bool resource_loader = false);
+                                                   bool for_loader = false);
 
   // Creates a totally empty ApkAssets with no resources table and no file entries.
-  static std::unique_ptr<const ApkAssets> LoadEmpty(bool resource_loader = false);
+  static std::unique_ptr<const ApkAssets> LoadEmpty(bool for_loader = false);
 
   std::unique_ptr<Asset> Open(const std::string& path,
                               Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
@@ -100,12 +100,12 @@
     return loaded_idmap_.get();
   }
 
-  inline bool IsOverlay() const {
-    return idmap_asset_.get() != nullptr;
+  inline bool IsLoader() const {
+    return (property_flags_ & PROPERTY_LOADER) != 0;
   }
 
-  inline bool IsLoader() const {
-    return for_loader_;
+  inline bool IsOverlay() const {
+    return (property_flags_ & PROPERTY_OVERLAY) != 0;
   }
 
   bool IsUpToDate() const;
@@ -119,24 +119,23 @@
   static std::unique_ptr<const ApkAssets> LoadImpl(base::unique_fd fd, const std::string& path,
                                                    std::unique_ptr<Asset> idmap_asset,
                                                    std::unique_ptr<const LoadedIdmap> loaded_idmap,
-                                                   bool system, bool load_as_shared_library,
-                                                   bool resource_loader = false);
+                                                   package_property_t property_flags);
 
   static std::unique_ptr<const ApkAssets> LoadArscImpl(base::unique_fd fd,
                                                        const std::string& path,
-                                                       bool resource_loader = false);
+                                                       package_property_t property_flags);
 
   ApkAssets(ZipArchiveHandle unmanaged_handle,
             const std::string& path,
             time_t last_mod_time,
-            bool for_loader = false);
+            package_property_t property_flags);
 
   using ZipArchivePtr = std::unique_ptr<ZipArchive, void (*)(ZipArchiveHandle)>;
 
   ZipArchivePtr zip_handle_;
   const std::string path_;
   time_t last_mod_time_;
-  bool for_loader_;
+  package_property_t property_flags_ = 0U;
   std::unique_ptr<Asset> resources_asset_;
   std::unique_ptr<Asset> idmap_asset_;
   std::unique_ptr<const LoadedArsc> loaded_arsc_;
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 20e4023..00cbbca 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -263,10 +263,13 @@
   // Creates a new Theme from this AssetManager.
   std::unique_ptr<Theme> NewTheme();
 
-  void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func) const {
+  void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func,
+                      package_property_t excluded_property_flags = 0U) const {
     for (const PackageGroup& package_group : package_groups_) {
-      if (!func(package_group.packages_.front().loaded_package_->GetPackageName(),
-           package_group.dynamic_ref_table->mAssignedPackageId)) {
+      const auto loaded_package = package_group.packages_.front().loaded_package_;
+      if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
+          && !func(loaded_package->GetPackageName(),
+                   package_group.dynamic_ref_table->mAssignedPackageId)) {
         return;
       }
     }
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index ba1beaa..6cbda07 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -69,6 +69,14 @@
   }
 };
 
+using package_property_t = uint32_t;
+enum : package_property_t {
+  PROPERTY_DYNAMIC = 1,
+  PROPERTY_LOADER = 2,
+  PROPERTY_OVERLAY = 4,
+  PROPERTY_SYSTEM = 8,
+};
+
 // TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
 // ResTable_type pointers.
 // TypeSpecPtr is a managed pointer that knows how to delete itself.
@@ -131,9 +139,8 @@
     return iterator(this, resource_ids_.size() + 1, 0);
   }
 
-  static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk, bool system,
-                                                   bool load_as_shared_library,
-                                                   bool load_as_custom_loader);
+  static std::unique_ptr<const LoadedPackage> Load(const Chunk& chunk,
+                                                   package_property_t property_flags);
 
   ~LoadedPackage();
 
@@ -170,17 +177,26 @@
 
   // Returns true if this package is dynamic (shared library) and needs to have an ID assigned.
   inline bool IsDynamic() const {
-    return dynamic_;
+    return (property_flags_ & PROPERTY_DYNAMIC) != 0;
+  }
+
+  // Returns true if this package is a Runtime Resource Overlay.
+  inline bool IsOverlay() const {
+    return (property_flags_ & PROPERTY_OVERLAY) != 0;
   }
 
   // Returns true if this package originates from a system provided resource.
   inline bool IsSystem() const {
-    return system_;
+    return (property_flags_ & PROPERTY_SYSTEM) != 0;
   }
 
-  // Returns true if this package is a custom loader and should behave like an overlay
+  // Returns true if this package is a custom loader and should behave like an overlay.
   inline bool IsCustomLoader() const {
-    return custom_loader_;
+    return (property_flags_ & PROPERTY_LOADER) != 0;
+  }
+
+  inline package_property_t GetPropertyFlags() const {
+    return property_flags_;
   }
 
   // Returns the map of package name to package ID used in this LoadedPackage. At runtime, a
@@ -248,12 +264,10 @@
   ResStringPool type_string_pool_;
   ResStringPool key_string_pool_;
   std::string package_name_;
+  bool defines_overlayable_ = false;
   int package_id_ = -1;
   int type_id_offset_ = 0;
-  bool dynamic_ = false;
-  bool system_ = false;
-  bool custom_loader_ = false;
-  bool defines_overlayable_ = false;
+  package_property_t property_flags_ = 0U;
 
   ByteBucketArray<TypeSpecPtr> type_specs_;
   ByteBucketArray<uint32_t> resource_ids_;
@@ -274,9 +288,7 @@
   // ID.
   static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data,
                                                 const LoadedIdmap* loaded_idmap = nullptr,
-                                                bool system = false,
-                                                bool load_as_shared_library = false,
-                                                bool for_loader = false);
+                                                package_property_t property_flags = 0U);
 
   // Create an empty LoadedArsc. This is used when an APK has no resources.arsc.
   static std::unique_ptr<const LoadedArsc> CreateEmpty();
@@ -296,28 +308,15 @@
     return packages_;
   }
 
-  // Returns true if this is a system provided resource.
-  inline bool IsSystem() const {
-    return system_;
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
 
   LoadedArsc() = default;
-  bool LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap, bool load_as_shared_library,
-                 bool for_loader);
-
-  static std::unique_ptr<const LoadedArsc> LoadData(std::unique_ptr<LoadedArsc>& loaded_arsc,
-                                                    const char* data,
-                                                    size_t length,
-                                                    const LoadedIdmap* loaded_idmap = nullptr,
-                                                    bool load_as_shared_library = false,
-                                                    bool for_loader = false);
+  bool LoadTable(
+      const Chunk& chunk, const LoadedIdmap* loaded_idmap, package_property_t property_flags);
 
   std::unique_ptr<ResStringPool> global_string_pool_ = util::make_unique<ResStringPool>();
   std::vector<std::unique_ptr<const LoadedPackage>> packages_;
-  bool system_ = false;
 };
 
 }  // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 82dd335..8615069 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -144,8 +144,7 @@
                                       "resources.arsc", &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(StringPiece(contents), nullptr /* loaded_idmap */, false /*system*/,
-                       true /*load_as_shared_library*/);
+      LoadedArsc::Load(StringPiece(contents), nullptr /* loaded_idmap */, PROPERTY_DYNAMIC);
   ASSERT_THAT(loaded_arsc, NotNull());
 
   const auto& packages = loaded_arsc->GetPackages();
@@ -227,9 +226,7 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
                                       "resources.arsc", &contents));
 
-  std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(StringPiece(contents), nullptr /* loaded_idmap */, false /*system*/,
-                       false /*load_as_shared_library*/);
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
 
   ASSERT_THAT(loaded_arsc, NotNull());
   const LoadedPackage* package = loaded_arsc->GetPackageById(
@@ -346,7 +343,7 @@
       asset->getLength());
 
   std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(data, nullptr, false, false, true);
+      LoadedArsc::Load(data, nullptr, PROPERTY_LOADER);
   ASSERT_THAT(loaded_arsc, NotNull());
 
   const LoadedPackage* package =
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index ecfaec2..f670cf9 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -235,12 +235,10 @@
                 "renderthread/RenderProxy.cpp",
                 "renderthread/RenderThread.cpp",
                 "service/GraphicsStatsService.cpp",
-                "surfacetexture/EGLConsumer.cpp",
-                "surfacetexture/ImageConsumer.cpp",
-                "surfacetexture/SurfaceTexture.cpp",
                 "thread/CommonPool.cpp",
                 "utils/GLUtils.cpp",
                 "utils/StringUtils.cpp",
+                "AutoBackendTextureRelease.cpp",
                 "DeferredLayerUpdater.cpp",
                 "DeviceInfo.cpp",
                 "FrameInfo.cpp",
diff --git a/libs/hwui/AutoBackendTextureRelease.cpp b/libs/hwui/AutoBackendTextureRelease.cpp
new file mode 100644
index 0000000..72747e8
--- /dev/null
+++ b/libs/hwui/AutoBackendTextureRelease.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AutoBackendTextureRelease.h"
+
+#include "renderthread/RenderThread.h"
+#include "utils/Color.h"
+#include "utils/PaintUtils.h"
+
+using namespace android::uirenderer::renderthread;
+
+namespace android {
+namespace uirenderer {
+
+AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer) {
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer_describe(buffer, &desc);
+    bool createProtectedImage = 0 != (desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT);
+    GrBackendFormat backendFormat =
+            GrAHardwareBufferUtils::GetBackendFormat(context, buffer, desc.format, false);
+    mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
+            context, buffer, desc.width, desc.height, &mDeleteProc, &mUpdateProc, &mImageCtx,
+            createProtectedImage, backendFormat, false);
+}
+
+void AutoBackendTextureRelease::unref(bool releaseImage) {
+    if (!RenderThread::isCurrent()) {
+        // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
+        // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
+        // thread safe.
+        RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
+        return;
+    }
+
+    if (releaseImage) {
+        mImage.reset();
+    }
+
+    mUsageCount--;
+    if (mUsageCount <= 0) {
+        if (mBackendTexture.isValid()) {
+            mDeleteProc(mImageCtx);
+            mBackendTexture = {};
+        }
+        delete this;
+    }
+}
+
+// releaseProc is invoked by SkImage, when texture is no longer in use.
+// "releaseContext" contains an "AutoBackendTextureRelease*".
+static void releaseProc(SkImage::ReleaseContext releaseContext) {
+    AutoBackendTextureRelease* textureRelease =
+            reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
+    textureRelease->unref(false);
+}
+
+void AutoBackendTextureRelease::makeImage(AHardwareBuffer* buffer, android_dataspace dataspace,
+                                          GrContext* context) {
+    AHardwareBuffer_Desc desc;
+    AHardwareBuffer_describe(buffer, &desc);
+    SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(desc.format);
+    mImage = SkImage::MakeFromTexture(
+            context, mBackendTexture, kTopLeft_GrSurfaceOrigin, colorType, kPremul_SkAlphaType,
+            uirenderer::DataSpaceToColorSpace(dataspace), releaseProc, this);
+    if (mImage.get()) {
+        // The following ref will be counteracted by releaseProc, when SkImage is discarded.
+        ref();
+    }
+}
+
+void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
+    if (mBackendTexture.isValid()) {
+        mUpdateProc(mImageCtx, context);
+    }
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/AutoBackendTextureRelease.h b/libs/hwui/AutoBackendTextureRelease.h
new file mode 100644
index 0000000..acdd63c
--- /dev/null
+++ b/libs/hwui/AutoBackendTextureRelease.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <GrAHardwareBufferUtils.h>
+#include <GrBackendSurface.h>
+#include <SkImage.h>
+#include <android/hardware_buffer.h>
+#include <system/graphics.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
+ * that keeps GPU resources alive until the last SkImage object using them is destroyed.
+ */
+class AutoBackendTextureRelease final {
+public:
+    AutoBackendTextureRelease(GrContext* context, AHardwareBuffer* buffer);
+
+    const GrBackendTexture& getTexture() const { return mBackendTexture; }
+
+    // Only called on the RenderThread, so it need not be thread-safe.
+    void ref() { mUsageCount++; }
+
+    void unref(bool releaseImage);
+
+    inline sk_sp<SkImage> getImage() const { return mImage; }
+
+    void makeImage(AHardwareBuffer* buffer, android_dataspace dataspace, GrContext* context);
+
+    void newBufferContent(GrContext* context);
+
+private:
+    // The only way to invoke dtor is with unref, when mUsageCount is 0.
+    ~AutoBackendTextureRelease() {}
+
+    GrBackendTexture mBackendTexture;
+    GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
+    GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
+    GrAHardwareBufferUtils::TexImageCtx mImageCtx;
+
+    // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
+    // are held by SkImages.
+    int mUsageCount = 1;
+
+    // mImage is the SkImage created from mBackendTexture.
+    sk_sp<SkImage> mImage;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index f300703..d6b516f 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -18,8 +18,15 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include "AutoBackendTextureRelease.h"
+#include "Matrix.h"
+#include "Properties.h"
 #include "renderstate/RenderState.h"
-#include "utils/PaintUtils.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/RenderThread.h"
+#include "renderthread/VulkanManager.h"
+
+using namespace android::uirenderer::renderthread;
 
 namespace android {
 namespace uirenderer {
@@ -27,7 +34,6 @@
 DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState)
         : mRenderState(renderState)
         , mBlend(false)
-        , mSurfaceTexture(nullptr)
         , mTransform(nullptr)
         , mGLContextAttached(false)
         , mUpdateTexImage(false)
@@ -41,14 +47,12 @@
     destroyLayer();
 }
 
-void DeferredLayerUpdater::setSurfaceTexture(const sp<SurfaceTexture>& consumer) {
-    if (consumer.get() != mSurfaceTexture.get()) {
-        mSurfaceTexture = consumer;
+void DeferredLayerUpdater::setSurfaceTexture(AutoTextureRelease&& consumer) {
+    mSurfaceTexture = std::move(consumer);
 
-        GLenum target = consumer->getCurrentTextureTarget();
-        LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
-                            "set unsupported SurfaceTexture with target %x", target);
-    }
+    GLenum target = ASurfaceTexture_getCurrentTextureTarget(mSurfaceTexture.get());
+    LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
+                        "set unsupported SurfaceTexture with target %x", target);
 }
 
 void DeferredLayerUpdater::onContextDestroyed() {
@@ -61,13 +65,15 @@
     }
 
     if (mSurfaceTexture.get() && mGLContextAttached) {
-        mSurfaceTexture->detachFromView();
+        ASurfaceTexture_releaseConsumerOwnership(mSurfaceTexture.get());
         mGLContextAttached = false;
     }
 
     mLayer->postDecStrong();
 
     mLayer = nullptr;
+
+    mImageSlots.clear();
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
@@ -80,6 +86,35 @@
     }
 }
 
+static status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, EGLDisplay* display,
+                                   int* releaseFence, void* handle) {
+    *display = EGL_NO_DISPLAY;
+    RenderState* renderState = (RenderState*)handle;
+    status_t err;
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        EglManager& eglManager = renderState->getRenderThread().eglManager();
+        *display = eglManager.eglDisplay();
+        err = eglManager.createReleaseFence(useFenceSync, eglFence, releaseFence);
+    } else {
+        err = renderState->getRenderThread().vulkanManager().createReleaseFence(
+                releaseFence, renderState->getRenderThread().getGrContext());
+    }
+    return err;
+}
+
+static status_t fenceWait(int fence, void* handle) {
+    // Wait on the producer fence for the buffer to be ready.
+    status_t err;
+    RenderState* renderState = (RenderState*)handle;
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        err = renderState->getRenderThread().eglManager().fenceWait(fence);
+    } else {
+        err = renderState->getRenderThread().vulkanManager().fenceWait(
+                fence, renderState->getRenderThread().getGrContext());
+    }
+    return err;
+}
+
 void DeferredLayerUpdater::apply() {
     if (!mLayer) {
         mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode);
@@ -92,24 +127,33 @@
         if (!mGLContextAttached) {
             mGLContextAttached = true;
             mUpdateTexImage = true;
-            mSurfaceTexture->attachToView();
+            ASurfaceTexture_takeConsumerOwnership(mSurfaceTexture.get());
         }
         if (mUpdateTexImage) {
             mUpdateTexImage = false;
-            sk_sp<SkImage> layerImage;
-            SkMatrix textureTransform;
-            bool queueEmpty = true;
-            // If the SurfaceTexture queue is in synchronous mode, need to discard all
-            // but latest frame. Since we can't tell which mode it is in,
-            // do this unconditionally.
-            do {
-                layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty,
-                        mRenderState);
-            } while (layerImage.get() && (!queueEmpty));
-            if (layerImage.get()) {
-                // force filtration if buffer size != layer size
-                bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height();
-                updateLayer(forceFilter, textureTransform, layerImage);
+            float transformMatrix[16];
+            android_dataspace dataspace;
+            int slot;
+            bool newContent = false;
+            // Note: ASurfaceTexture_dequeueBuffer discards all but the last frame. This
+            // is necessary if the SurfaceTexture queue is in synchronous mode, and we
+            // cannot tell which mode it is in.
+            AHardwareBuffer* hardwareBuffer = ASurfaceTexture_dequeueBuffer(
+                    mSurfaceTexture.get(), &slot, &dataspace, transformMatrix, &newContent,
+                    createReleaseFence, fenceWait, &mRenderState);
+
+            if (hardwareBuffer) {
+                sk_sp<SkImage> layerImage = mImageSlots[slot].createIfNeeded(
+                        hardwareBuffer, dataspace, newContent,
+                        mRenderState.getRenderThread().getGrContext());
+                if (layerImage.get()) {
+                    SkMatrix textureTransform;
+                    mat4(transformMatrix).copyTo(textureTransform);
+                    // force filtration if buffer size != layer size
+                    bool forceFilter =
+                            mWidth != layerImage->width() || mHeight != layerImage->height();
+                    updateLayer(forceFilter, textureTransform, layerImage);
+                }
             }
         }
 
@@ -121,7 +165,7 @@
 }
 
 void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform,
-        const sk_sp<SkImage>& layerImage) {
+                                       const sk_sp<SkImage>& layerImage) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
@@ -136,5 +180,42 @@
     }
 }
 
+sk_sp<SkImage> DeferredLayerUpdater::ImageSlot::createIfNeeded(AHardwareBuffer* buffer,
+                                                               android_dataspace dataspace,
+                                                               bool forceCreate,
+                                                               GrContext* context) {
+    if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace ||
+        forceCreate || mBuffer != buffer) {
+        if (buffer != mBuffer) {
+            clear();
+        }
+
+        if (!buffer) {
+            return nullptr;
+        }
+
+        if (!mTextureRelease) {
+            mTextureRelease = new AutoBackendTextureRelease(context, buffer);
+        } else {
+            mTextureRelease->newBufferContent(context);
+        }
+
+        mDataspace = dataspace;
+        mBuffer = buffer;
+        mTextureRelease->makeImage(buffer, dataspace, context);
+    }
+    return mTextureRelease ? mTextureRelease->getImage() : nullptr;
+}
+
+void DeferredLayerUpdater::ImageSlot::clear() {
+    if (mTextureRelease) {
+        // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
+        mTextureRelease->unref(true);
+        mTextureRelease = nullptr;
+    }
+
+    mBuffer = nullptr;
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 1491f99..289f65c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -19,21 +19,26 @@
 #include <SkColorFilter.h>
 #include <SkImage.h>
 #include <SkMatrix.h>
+#include <android/hardware_buffer.h>
 #include <cutils/compiler.h>
-#include <map>
-#include <system/graphics.h>
-#include <utils/StrongPointer.h>
+// TODO: Use public SurfaceTexture APIs once available and include public NDK header file instead.
+#include <gui/surfacetexture/surface_texture_platform.h>
 
-#include "renderstate/RenderState.h"
-#include "surfacetexture/SurfaceTexture.h"
+#include <map>
+#include <memory>
+
 #include "Layer.h"
 #include "Rect.h"
+#include "renderstate/RenderState.h"
 
 namespace android {
 namespace uirenderer {
 
+class AutoBackendTextureRelease;
 class RenderState;
 
+typedef std::unique_ptr<ASurfaceTexture> AutoTextureRelease;
+
 // Container to hold the properties a layer should be set to at the start
 // of a render pass
 class DeferredLayerUpdater : public VirtualLightRefBase, public IGpuContextCallback {
@@ -64,7 +69,7 @@
         return false;
     }
 
-    ANDROID_API void setSurfaceTexture(const sp<SurfaceTexture>& consumer);
+    ANDROID_API void setSurfaceTexture(AutoTextureRelease&& consumer);
 
     ANDROID_API void updateTexImage() { mUpdateTexImage = true; }
 
@@ -92,6 +97,39 @@
     void onContextDestroyed() override;
 
 private:
+    /**
+     * ImageSlot contains the information and object references that
+     * DeferredLayerUpdater maintains about a slot. Slot id comes from
+     * ASurfaceTexture_dequeueBuffer. Usually there are at most 3 slots active at a time.
+     */
+    class ImageSlot {
+    public:
+        ~ImageSlot() { clear(); }
+
+        sk_sp<SkImage> createIfNeeded(AHardwareBuffer* buffer, android_dataspace dataspace,
+                                      bool forceCreate, GrContext* context);
+
+    private:
+        void clear();
+
+        // the dataspace associated with the current image
+        android_dataspace mDataspace = HAL_DATASPACE_UNKNOWN;
+
+        AHardwareBuffer* mBuffer = nullptr;
+
+        /**
+         * mTextureRelease may outlive DeferredLayerUpdater, if the last ref is held by an SkImage.
+         * DeferredLayerUpdater holds one ref to mTextureRelease, which is decremented by "clear".
+         */
+        AutoBackendTextureRelease* mTextureRelease = nullptr;
+    };
+
+    /**
+     * DeferredLayerUpdater stores the SkImages that have been allocated by the BufferQueue
+     * for each buffer slot.
+     */
+    std::map<int, ImageSlot> mImageSlots;
+
     RenderState& mRenderState;
 
     // Generic properties
@@ -101,7 +139,7 @@
     sk_sp<SkColorFilter> mColorFilter;
     int mAlpha = 255;
     SkBlendMode mMode = SkBlendMode::kSrcOver;
-    sp<SurfaceTexture> mSurfaceTexture;
+    AutoTextureRelease mSurfaceTexture;
     SkMatrix* mTransform;
     bool mGLContextAttached;
     bool mUpdateTexImage;
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 87ef7fc..0647977 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -366,12 +366,12 @@
     // capture is enabled.
     SkCanvas* canvas = tryCapture(surface.get());
 
-    renderFrameImpl(layers, clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
+    renderFrameImpl(clip, nodes, opaque, contentDrawBounds, canvas, preTransform);
 
     endCapture(surface.get());
 
     if (CC_UNLIKELY(Properties::debugOverdraw)) {
-        renderOverdraw(layers, clip, nodes, contentDrawBounds, surface, preTransform);
+        renderOverdraw(clip, nodes, contentDrawBounds, surface, preTransform);
     }
 
     ATRACE_NAME("flush commands");
@@ -387,7 +387,7 @@
 }
 }  // namespace
 
-void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+void SkiaPipeline::renderFrameImpl(const SkRect& clip,
                                    const std::vector<sp<RenderNode>>& nodes, bool opaque,
                                    const Rect& contentDrawBounds, SkCanvas* canvas,
                                    const SkMatrix& preTransform) {
@@ -539,7 +539,7 @@
         },
 };
 
-void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+void SkiaPipeline::renderOverdraw(const SkRect& clip,
                                   const std::vector<sp<RenderNode>>& nodes,
                                   const Rect& contentDrawBounds, sk_sp<SkSurface> surface,
                                   const SkMatrix& preTransform) {
@@ -553,7 +553,7 @@
     // each time a pixel would have been drawn.
     // Pass true for opaque so we skip the clear - the overdrawCanvas is already zero
     // initialized.
-    renderFrameImpl(layers, clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
+    renderFrameImpl(clip, nodes, true, contentDrawBounds, &overdrawCanvas, preTransform);
     sk_sp<SkImage> counts = offscreen->makeImageSnapshot();
 
     // Draw overdraw colors to the canvas.  The color filter will convert counts to colors.
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 215ff36..7d575ad 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -77,7 +77,7 @@
     sk_sp<SkColorSpace> mSurfaceColorSpace;
 
 private:
-    void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
+    void renderFrameImpl(const SkRect& clip,
                          const std::vector<sp<RenderNode>>& nodes, bool opaque,
                          const Rect& contentDrawBounds, SkCanvas* canvas,
                          const SkMatrix& preTransform);
@@ -86,7 +86,7 @@
      *  Debugging feature.  Draws a semi-transparent overlay on each pixel, indicating
      *  how many times it has been drawn.
      */
-    void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
+    void renderOverdraw(const SkRect& clip,
                         const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds,
                         sk_sp<SkSurface> surface, const SkMatrix& preTransform);
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 826a8ea..f086768 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -147,7 +147,6 @@
         mNativeSurface = new ReliableSurface{std::move(surface)};
         // TODO: Fix error handling & re-shorten timeout
         ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
-        mNativeSurface->enableFrameTimestamps(true);
     } else {
         mNativeSurface = nullptr;
     }
@@ -169,6 +168,10 @@
     if (hasSurface) {
         mHaveNewSurface = true;
         mSwapHistory.clear();
+        // Enable frame stats after the surface has been bound to the appropriate graphics API.
+        // Order is important when new and old surfaces are the same, because old surface has
+        // its frame stats disabled automatically.
+        mNativeSurface->enableFrameTimestamps(true);
     } else {
         mRenderThread.removeFrameCallback(this);
         mGenerationID++;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 1202164..eb469a8 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -16,22 +16,22 @@
 
 #include "EglManager.h"
 
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
 #include <cutils/properties.h>
 #include <log/log.h>
 #include <private/gui/SyncFeatures.h>
+#include <sync/sync.h>
+#include <system/window.h>
 #include <utils/Trace.h>
-#include "utils/Color.h"
-#include "utils/StringUtils.h"
+
+#include <string>
+#include <vector>
 
 #include "Frame.h"
 #include "Properties.h"
-
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-
-#include <system/window.h>
-#include <string>
-#include <vector>
+#include "utils/Color.h"
+#include "utils/StringUtils.h"
 
 #define GLES_VERSION 2
 
@@ -508,7 +508,21 @@
     return preserved;
 }
 
-status_t EglManager::fenceWait(sp<Fence>& fence) {
+static status_t waitForeverOnFence(int fence, const char* logname) {
+    ATRACE_CALL();
+    if (fence == -1) {
+        return NO_ERROR;
+    }
+    constexpr int warningTimeout = 3000;
+    int err = sync_wait(fence, warningTimeout);
+    if (err < 0 && errno == ETIME) {
+        ALOGE("%s: fence %d didn't signal in %d ms", logname, fence, warningTimeout);
+        err = sync_wait(fence, -1);
+    }
+    return err < 0 ? -errno : status_t(NO_ERROR);
+}
+
+status_t EglManager::fenceWait(int fence) {
     if (!hasEglContext()) {
         ALOGE("EglManager::fenceWait: EGLDisplay not initialized");
         return INVALID_OPERATION;
@@ -518,7 +532,7 @@
         SyncFeatures::getInstance().useNativeFenceSync()) {
         // Block GPU on the fence.
         // Create an EGLSyncKHR from the current fence.
-        int fenceFd = fence->dup();
+        int fenceFd = ::dup(fence);
         if (fenceFd == -1) {
             ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno);
             return -errno;
@@ -543,7 +557,7 @@
         }
     } else {
         // Block CPU on the fence.
-        status_t err = fence->waitForever("EglManager::fenceWait");
+        status_t err = waitForeverOnFence(fence, "EglManager::fenceWait");
         if (err != NO_ERROR) {
             ALOGE("EglManager::fenceWait: error waiting for fence: %d", err);
             return err;
@@ -552,8 +566,8 @@
     return OK;
 }
 
-status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence,
-                                        sp<Fence>& nativeFence) {
+status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, int* nativeFence) {
+    *nativeFence = -1;
     if (!hasEglContext()) {
         ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized");
         return INVALID_OPERATION;
@@ -574,7 +588,7 @@
                   eglGetError());
             return UNKNOWN_ERROR;
         }
-        nativeFence = new Fence(fenceFd);
+        *nativeFence = fenceFd;
         *eglFence = EGL_NO_SYNC_KHR;
     } else if (useFenceSync && SyncFeatures::getInstance().useFenceSync()) {
         if (*eglFence != EGL_NO_SYNC_KHR) {
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 27d41d2..a893e24 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -21,9 +21,9 @@
 #include <SkImageInfo.h>
 #include <SkRect.h>
 #include <cutils/compiler.h>
-#include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
+
 #include "IRenderPipeline.h"
 #include "utils/Result.h"
 
@@ -74,11 +74,11 @@
 
     // Inserts a wait on fence command into the OpenGL ES command stream. If EGL extension
     // support is missing, block the CPU on the fence.
-    status_t fenceWait(sp<Fence>& fence);
+    status_t fenceWait(int fence);
 
     // Creates a fence that is signaled, when all the pending GL commands are flushed.
     // Depending on installed extensions, the result is either Android native fence or EGL fence.
-    status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence);
+    status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, int* nativeFence);
 
 private:
     enum class SwapBehavior {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index bdd80721..da79e97 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -17,33 +17,32 @@
 #ifndef RENDERTHREAD_H_
 #define RENDERTHREAD_H_
 
-#include "RenderTask.h"
+#include <GrContext.h>
+#include <SkBitmap.h>
+#include <cutils/compiler.h>
+#include <thread/ThreadBase.h>
+#include <utils/Looper.h>
+#include <utils/Thread.h>
+
+#include <memory>
+#include <mutex>
+#include <set>
 
 #include "CacheManager.h"
 #include "ProfileDataContainer.h"
+#include "RenderTask.h"
 #include "TimeLord.h"
 #include "WebViewFunctorManager.h"
 #include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
-#include <GrContext.h>
-#include <SkBitmap.h>
-#include <cutils/compiler.h>
-#include <utils/Looper.h>
-#include <utils/Thread.h>
-
-#include <thread/ThreadBase.h>
-#include <memory>
-#include <mutex>
-#include <set>
-
 namespace android {
 
 class Bitmap;
-class AutoBackendTextureRelease;
 
 namespace uirenderer {
 
+class AutoBackendTextureRelease;
 class Readback;
 class RenderState;
 class TestUtils;
@@ -137,7 +136,7 @@
     friend class DispatchFrameCallbacks;
     friend class RenderProxy;
     friend class DummyVsyncSource;
-    friend class android::AutoBackendTextureRelease;
+    friend class android::uirenderer::AutoBackendTextureRelease;
     friend class android::uirenderer::TestUtils;
     friend class android::uirenderer::WebViewFunctor;
     friend class android::uirenderer::skiapipeline::VkFunctorDrawHandler;
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 35abc57..a5355fc 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,9 +16,15 @@
 
 #include "VulkanManager.h"
 
-#include <android/sync.h>
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
+#include <GrBackendSemaphore.h>
+#include <GrBackendSurface.h>
+#include <GrContext.h>
+#include <GrTypes.h>
+#include <android/sync.h>
+#include <vk/GrVkExtensions.h>
+#include <vk/GrVkTypes.h>
 
 #include "Properties.h"
 #include "RenderThread.h"
@@ -26,13 +32,6 @@
 #include "utils/FatVector.h"
 #include "utils/TraceUtils.h"
 
-#include <GrBackendSemaphore.h>
-#include <GrBackendSurface.h>
-#include <GrContext.h>
-#include <GrTypes.h>
-#include <vk/GrVkExtensions.h>
-#include <vk/GrVkTypes.h>
-
 namespace android {
 namespace uirenderer {
 namespace renderthread {
@@ -482,7 +481,7 @@
     int mRefs = 2;
 
     DestroySemaphoreInfo(PFN_vkDestroySemaphore destroyFunction, VkDevice device,
-            VkSemaphore semaphore)
+                         VkSemaphore semaphore)
             : mDestroyFunction(destroyFunction), mDevice(device), mSemaphore(semaphore) {}
 };
 
@@ -524,12 +523,11 @@
     backendSemaphore.initVulkan(semaphore);
 
     int fenceFd = -1;
-    DestroySemaphoreInfo* destroyInfo = new DestroySemaphoreInfo(mDestroySemaphore, mDevice,
-                                                                 semaphore);
-    GrSemaphoresSubmitted submitted =
-            bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent,
-                                         kNone_GrFlushFlags, 1, &backendSemaphore,
-                                         destroy_semaphore, destroyInfo);
+    DestroySemaphoreInfo* destroyInfo =
+            new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
+    GrSemaphoresSubmitted submitted = bufferInfo->skSurface->flush(
+            SkSurface::BackendSurfaceAccess::kPresent, kNone_GrFlushFlags, 1, &backendSemaphore,
+            destroy_semaphore, destroyInfo);
     if (submitted == GrSemaphoresSubmitted::kYes) {
         VkSemaphoreGetFdInfoKHR getFdInfo;
         getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
@@ -571,14 +569,14 @@
                                  *this, extraBuffers);
 }
 
-status_t VulkanManager::fenceWait(sp<Fence>& fence, GrContext* grContext) {
+status_t VulkanManager::fenceWait(int fence, GrContext* grContext) {
     if (!hasVkContext()) {
         ALOGE("VulkanManager::fenceWait: VkDevice not initialized");
         return INVALID_OPERATION;
     }
 
     // Block GPU on the fence.
-    int fenceFd = fence->dup();
+    int fenceFd = ::dup(fence);
     if (fenceFd == -1) {
         ALOGE("VulkanManager::fenceWait: error dup'ing fence fd: %d", errno);
         return -errno;
@@ -619,7 +617,8 @@
     return OK;
 }
 
-status_t VulkanManager::createReleaseFence(sp<Fence>& nativeFence, GrContext* grContext) {
+status_t VulkanManager::createReleaseFence(int* nativeFence, GrContext* grContext) {
+    *nativeFence = -1;
     if (!hasVkContext()) {
         ALOGE("VulkanManager::createReleaseFence: VkDevice not initialized");
         return INVALID_OPERATION;
@@ -644,14 +643,13 @@
     GrBackendSemaphore backendSemaphore;
     backendSemaphore.initVulkan(semaphore);
 
-    DestroySemaphoreInfo* destroyInfo = new DestroySemaphoreInfo(mDestroySemaphore, mDevice,
-                                                                 semaphore);
+    DestroySemaphoreInfo* destroyInfo =
+            new DestroySemaphoreInfo(mDestroySemaphore, mDevice, semaphore);
     // Even if Skia fails to submit the semaphore, it will still call the destroy_semaphore callback
     // which will remove its ref to the semaphore. The VulkanManager must still release its ref,
     // when it is done with the semaphore.
-    GrSemaphoresSubmitted submitted =
-            grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore,
-                             destroy_semaphore, destroyInfo);
+    GrSemaphoresSubmitted submitted = grContext->flush(kNone_GrFlushFlags, 1, &backendSemaphore,
+                                                       destroy_semaphore, destroyInfo);
 
     if (submitted == GrSemaphoresSubmitted::kNo) {
         ALOGE("VulkanManager::createReleaseFence: Failed to submit semaphore");
@@ -673,7 +671,7 @@
         ALOGE("VulkanManager::createReleaseFence: Failed to get semaphore Fd");
         return INVALID_OPERATION;
     }
-    nativeFence = new Fence(fenceFd);
+    *nativeFence = fenceFd;
 
     return OK;
 }
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 4c6a755..8b19f13 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -20,14 +20,13 @@
 #if !defined(VK_USE_PLATFORM_ANDROID_KHR)
 #define VK_USE_PLATFORM_ANDROID_KHR
 #endif
-#include <vulkan/vulkan.h>
-
 #include <GrContextOptions.h>
 #include <SkSurface.h>
-#include <ui/Fence.h>
 #include <utils/StrongPointer.h>
 #include <vk/GrVkBackendContext.h>
 #include <vk/GrVkExtensions.h>
+#include <vulkan/vulkan.h>
+
 #include "Frame.h"
 #include "IRenderPipeline.h"
 #include "VulkanSurface.h"
@@ -71,11 +70,11 @@
     void destroy();
 
     // Inserts a wait on fence command into the Vulkan command buffer.
-    status_t fenceWait(sp<Fence>& fence, GrContext* grContext);
+    status_t fenceWait(int fence, GrContext* grContext);
 
     // Creates a fence that is signaled when all the pending Vulkan commands are finished on the
     // GPU.
-    status_t createReleaseFence(sp<Fence>& nativeFence, GrContext* grContext);
+    status_t createReleaseFence(int* nativeFence, GrContext* grContext);
 
     // Returned pointers are owned by VulkanManager.
     // An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to
diff --git a/libs/hwui/surfacetexture/EGLConsumer.cpp b/libs/hwui/surfacetexture/EGLConsumer.cpp
deleted file mode 100644
index 85b3917..0000000
--- a/libs/hwui/surfacetexture/EGLConsumer.cpp
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <cutils/compiler.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-#include <private/gui/SyncFeatures.h>
-#include "EGLConsumer.h"
-#include "SurfaceTexture.h"
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Trace.h>
-
-#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
-#define EGL_PROTECTED_CONTENT_EXT 0x32C0
-
-namespace android {
-
-// Macros for including the SurfaceTexture name in log messages
-#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-
-static const struct {
-    uint32_t width, height;
-    char const* bits;
-} kDebugData = {15, 12,
-                "_______________"
-                "_______________"
-                "_____XX_XX_____"
-                "__X_X_____X_X__"
-                "__X_XXXXXXX_X__"
-                "__XXXXXXXXXXX__"
-                "___XX_XXX_XX___"
-                "____XXXXXXX____"
-                "_____X___X_____"
-                "____X_____X____"
-                "_______________"
-                "_______________"};
-
-Mutex EGLConsumer::sStaticInitLock;
-sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer;
-
-static bool hasEglProtectedContentImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts);
-    bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1);
-    bool atEnd = (cropExtLen + 1) < extsLen &&
-                 !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1));
-    bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglProtectedContent() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglProtectedContentImpl();
-    return hasIt;
-}
-
-EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {}
-
-status_t EGLConsumer::updateTexImage(SurfaceTexture& st) {
-    // Make sure the EGL state is the same as in previous calls.
-    status_t err = checkAndUpdateEglStateLocked(st);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    BufferItem item;
-
-    // Acquire the next buffer.
-    // In asynchronous mode the list is guaranteed to be one buffer
-    // deep, while in synchronous mode we use the oldest buffer.
-    err = st.acquireBufferLocked(&item, 0);
-    if (err != NO_ERROR) {
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            // We always bind the texture even if we don't update its contents.
-            EGC_LOGV("updateTexImage: no buffers were available");
-            glBindTexture(st.mTexTarget, st.mTexName);
-            err = NO_ERROR;
-        } else {
-            EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
-        }
-        return err;
-    }
-
-    // Release the previous buffer.
-    err = updateAndReleaseLocked(item, nullptr, st);
-    if (err != NO_ERROR) {
-        // We always bind the texture.
-        glBindTexture(st.mTexTarget, st.mTexName);
-        return err;
-    }
-
-    // Bind the new buffer to the GL texture, and wait until it's ready.
-    return bindTextureImageLocked(st);
-}
-
-status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) {
-    // Make sure the EGL state is the same as in previous calls.
-    status_t err = NO_ERROR;
-
-    // if we're detached, no need to validate EGL's state -- we won't use it.
-    if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
-        err = checkAndUpdateEglStateLocked(st, true);
-        if (err != NO_ERROR) {
-            return err;
-        }
-    }
-
-    // Update the EGLConsumer state.
-    int buf = st.mCurrentTexture;
-    if (buf != BufferQueue::INVALID_BUFFER_SLOT) {
-        EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode);
-
-        // if we're detached, we just use the fence that was created in detachFromContext()
-        // so... basically, nothing more to do here.
-        if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
-            // Do whatever sync ops we need to do before releasing the slot.
-            err = syncForReleaseLocked(mEglDisplay, st);
-            if (err != NO_ERROR) {
-                EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err);
-                return err;
-            }
-        }
-
-        err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay,
-                                     EGL_NO_SYNC_KHR);
-        if (err < NO_ERROR) {
-            EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err);
-            return err;
-        }
-
-        if (mReleasedTexImage == nullptr) {
-            mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
-        }
-
-        st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
-        mCurrentTextureImage = mReleasedTexImage;
-        st.mCurrentCrop.makeInvalid();
-        st.mCurrentTransform = 0;
-        st.mCurrentTimestamp = 0;
-        st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN;
-        st.mCurrentFence = Fence::NO_FENCE;
-        st.mCurrentFenceTime = FenceTime::NO_FENCE;
-
-        // detached, don't touch the texture (and we may not even have an
-        // EGLDisplay here.
-        if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) {
-            // This binds a dummy buffer (mReleasedTexImage).
-            status_t result = bindTextureImageLocked(st);
-            if (result != NO_ERROR) {
-                return result;
-            }
-        }
-    }
-
-    return NO_ERROR;
-}
-
-sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() {
-    Mutex::Autolock _l(sStaticInitLock);
-    if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
-        // The first time, create the debug texture in case the application
-        // continues to use it.
-        sp<GraphicBuffer> buffer = new GraphicBuffer(
-                kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
-                GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]");
-        uint32_t* bits;
-        buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
-        uint32_t stride = buffer->getStride();
-        uint32_t height = buffer->getHeight();
-        memset(bits, 0, stride * height * 4);
-        for (uint32_t y = 0; y < kDebugData.height; y++) {
-            for (uint32_t x = 0; x < kDebugData.width; x++) {
-                bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000
-                                                                             : 0xFFFFFFFF;
-            }
-            bits += stride;
-        }
-        buffer->unlock();
-        sReleasedTexImageBuffer = buffer;
-    }
-    return sReleasedTexImageBuffer;
-}
-
-void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) {
-    // If item->mGraphicBuffer is not null, this buffer has not been acquired
-    // before, so any prior EglImage created is using a stale buffer. This
-    // replaces any old EglImage with a new one (using the new buffer).
-    int slot = item->mSlot;
-    if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) {
-        mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
-    }
-}
-
-void EGLConsumer::onReleaseBufferLocked(int buf) {
-    mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR;
-}
-
-status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
-                                             SurfaceTexture& st) {
-    status_t err = NO_ERROR;
-
-    int slot = item.mSlot;
-
-    if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) {
-        EGC_LOGE(
-                "updateAndRelease: EGLConsumer is not attached to an OpenGL "
-                "ES context");
-        st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
-        return INVALID_OPERATION;
-    }
-
-    // Confirm state.
-    err = checkAndUpdateEglStateLocked(st);
-    if (err != NO_ERROR) {
-        st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
-        return err;
-    }
-
-    // Ensure we have a valid EglImageKHR for the slot, creating an EglImage
-    // if nessessary, for the gralloc buffer currently in the slot in
-    // ConsumerBase.
-    // We may have to do this even when item.mGraphicBuffer == NULL (which
-    // means the buffer was previously acquired).
-    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
-    if (err != NO_ERROR) {
-        EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay,
-                 slot);
-        st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR);
-        return UNKNOWN_ERROR;
-    }
-
-    // Do whatever sync ops we need to do before releasing the old slot.
-    if (slot != st.mCurrentTexture) {
-        err = syncForReleaseLocked(mEglDisplay, st);
-        if (err != NO_ERROR) {
-            // Release the buffer we just acquired.  It's not safe to
-            // release the old buffer, so instead we just drop the new frame.
-            // As we are still under lock since acquireBuffer, it is safe to
-            // release by slot.
-            st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay,
-                                   EGL_NO_SYNC_KHR);
-            return err;
-        }
-    }
-
-    EGC_LOGV(
-            "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture,
-            mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr,
-            slot, st.mSlots[slot].mGraphicBuffer->handle);
-
-    // Hang onto the pointer so that it isn't freed in the call to
-    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
-    // the same.
-    sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage;
-
-    // release old buffer
-    if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (pendingRelease == nullptr) {
-            status_t status = st.releaseBufferLocked(
-                    st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay,
-                    mEglSlots[st.mCurrentTexture].mEglFence);
-            if (status < NO_ERROR) {
-                EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
-                         status);
-                err = status;
-                // keep going, with error raised [?]
-            }
-        } else {
-            pendingRelease->currentTexture = st.mCurrentTexture;
-            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
-            pendingRelease->display = mEglDisplay;
-            pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence;
-            pendingRelease->isPending = true;
-        }
-    }
-
-    // Update the EGLConsumer state.
-    st.mCurrentTexture = slot;
-    mCurrentTextureImage = nextTextureImage;
-    st.mCurrentCrop = item.mCrop;
-    st.mCurrentTransform = item.mTransform;
-    st.mCurrentScalingMode = item.mScalingMode;
-    st.mCurrentTimestamp = item.mTimestamp;
-    st.mCurrentDataSpace = item.mDataSpace;
-    st.mCurrentFence = item.mFence;
-    st.mCurrentFenceTime = item.mFenceTime;
-    st.mCurrentFrameNumber = item.mFrameNumber;
-
-    st.computeCurrentTransformMatrixLocked();
-
-    return err;
-}
-
-status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) {
-    if (mEglDisplay == EGL_NO_DISPLAY) {
-        ALOGE("bindTextureImage: invalid display");
-        return INVALID_OPERATION;
-    }
-
-    GLenum error;
-    while ((error = glGetError()) != GL_NO_ERROR) {
-        EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error);
-    }
-
-    glBindTexture(st.mTexTarget, st.mTexName);
-    if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) {
-        EGC_LOGE("bindTextureImage: no currently-bound texture");
-        return NO_INIT;
-    }
-
-    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
-    if (err != NO_ERROR) {
-        EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
-                 st.mCurrentTexture);
-        return UNKNOWN_ERROR;
-    }
-    mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
-
-    // In the rare case that the display is terminated and then initialized
-    // again, we can't detect that the display changed (it didn't), but the
-    // image is invalid. In this case, repeat the exact same steps while
-    // forcing the creation of a new image.
-    if ((error = glGetError()) != GL_NO_ERROR) {
-        glBindTexture(st.mTexTarget, st.mTexName);
-        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
-        if (result != NO_ERROR) {
-            EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay,
-                     st.mCurrentTexture);
-            return UNKNOWN_ERROR;
-        }
-        mCurrentTextureImage->bindToTextureTarget(st.mTexTarget);
-        if ((error = glGetError()) != GL_NO_ERROR) {
-            EGC_LOGE("bindTextureImage: error binding external image: %#04x", error);
-            return UNKNOWN_ERROR;
-        }
-    }
-
-    // Wait for the new buffer to be ready.
-    return doGLFenceWaitLocked(st);
-}
-
-status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) {
-    EGLDisplay dpy = eglGetCurrentDisplay();
-    EGLContext ctx = eglGetCurrentContext();
-
-    if (!contextCheck) {
-        // if this is the first time we're called, mEglDisplay/mEglContext have
-        // never been set, so don't error out (below).
-        if (mEglDisplay == EGL_NO_DISPLAY) {
-            mEglDisplay = dpy;
-        }
-        if (mEglContext == EGL_NO_CONTEXT) {
-            mEglContext = ctx;
-        }
-    }
-
-    if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) {
-        EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay");
-        return INVALID_OPERATION;
-    }
-
-    if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) {
-        EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext");
-        return INVALID_OPERATION;
-    }
-
-    mEglDisplay = dpy;
-    mEglContext = ctx;
-    return NO_ERROR;
-}
-
-status_t EGLConsumer::detachFromContext(SurfaceTexture& st) {
-    EGLDisplay dpy = eglGetCurrentDisplay();
-    EGLContext ctx = eglGetCurrentContext();
-
-    if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) {
-        EGC_LOGE("detachFromContext: invalid current EGLDisplay");
-        return INVALID_OPERATION;
-    }
-
-    if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) {
-        EGC_LOGE("detachFromContext: invalid current EGLContext");
-        return INVALID_OPERATION;
-    }
-
-    if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) {
-        status_t err = syncForReleaseLocked(dpy, st);
-        if (err != OK) {
-            return err;
-        }
-
-        glDeleteTextures(1, &st.mTexName);
-    }
-
-    mEglDisplay = EGL_NO_DISPLAY;
-    mEglContext = EGL_NO_CONTEXT;
-
-    return OK;
-}
-
-status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) {
-    // Initialize mCurrentTextureImage if there is a current buffer from past attached state.
-    int slot = st.mCurrentTexture;
-    if (slot != BufferItem::INVALID_BUFFER_SLOT) {
-        if (!mEglSlots[slot].mEglImage.get()) {
-            mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer);
-        }
-        mCurrentTextureImage = mEglSlots[slot].mEglImage;
-    }
-
-    EGLDisplay dpy = eglGetCurrentDisplay();
-    EGLContext ctx = eglGetCurrentContext();
-
-    if (dpy == EGL_NO_DISPLAY) {
-        EGC_LOGE("attachToContext: invalid current EGLDisplay");
-        return INVALID_OPERATION;
-    }
-
-    if (ctx == EGL_NO_CONTEXT) {
-        EGC_LOGE("attachToContext: invalid current EGLContext");
-        return INVALID_OPERATION;
-    }
-
-    // We need to bind the texture regardless of whether there's a current
-    // buffer.
-    glBindTexture(st.mTexTarget, GLuint(tex));
-
-    mEglDisplay = dpy;
-    mEglContext = ctx;
-    st.mTexName = tex;
-    st.mOpMode = SurfaceTexture::OpMode::attachedToGL;
-
-    if (mCurrentTextureImage != nullptr) {
-        // This may wait for a buffer a second time. This is likely required if
-        // this is a different context, since otherwise the wait could be skipped
-        // by bouncing through another context. For the same context the extra
-        // wait is redundant.
-        status_t err = bindTextureImageLocked(st);
-        if (err != NO_ERROR) {
-            return err;
-        }
-    }
-
-    return OK;
-}
-
-status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) {
-    EGC_LOGV("syncForReleaseLocked");
-
-    if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (SyncFeatures::getInstance().useNativeFenceSync()) {
-            EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
-            if (sync == EGL_NO_SYNC_KHR) {
-                EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError());
-                return UNKNOWN_ERROR;
-            }
-            glFlush();
-            int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
-            eglDestroySyncKHR(dpy, sync);
-            if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-                EGC_LOGE(
-                        "syncForReleaseLocked: error dup'ing native fence "
-                        "fd: %#x",
-                        eglGetError());
-                return UNKNOWN_ERROR;
-            }
-            sp<Fence> fence(new Fence(fenceFd));
-            status_t err = st.addReleaseFenceLocked(st.mCurrentTexture,
-                                                    mCurrentTextureImage->graphicBuffer(), fence);
-            if (err != OK) {
-                EGC_LOGE(
-                        "syncForReleaseLocked: error adding release fence: "
-                        "%s (%d)",
-                        strerror(-err), err);
-                return err;
-            }
-        } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) {
-            EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence;
-            if (fence != EGL_NO_SYNC_KHR) {
-                // There is already a fence for the current slot.  We need to
-                // wait on that before replacing it with another fence to
-                // ensure that all outstanding buffer accesses have completed
-                // before the producer accesses it.
-                EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
-                if (result == EGL_FALSE) {
-                    EGC_LOGE(
-                            "syncForReleaseLocked: error waiting for previous "
-                            "fence: %#x",
-                            eglGetError());
-                    return UNKNOWN_ERROR;
-                } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                    EGC_LOGE(
-                            "syncForReleaseLocked: timeout waiting for previous "
-                            "fence");
-                    return TIMED_OUT;
-                }
-                eglDestroySyncKHR(dpy, fence);
-            }
-
-            // Create a fence for the outstanding accesses in the current
-            // OpenGL ES context.
-            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
-            if (fence == EGL_NO_SYNC_KHR) {
-                EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError());
-                return UNKNOWN_ERROR;
-            }
-            glFlush();
-            mEglSlots[st.mCurrentTexture].mEglFence = fence;
-        }
-    }
-
-    return OK;
-}
-
-status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const {
-    EGLDisplay dpy = eglGetCurrentDisplay();
-    EGLContext ctx = eglGetCurrentContext();
-
-    if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
-        EGC_LOGE("doGLFenceWait: invalid current EGLDisplay");
-        return INVALID_OPERATION;
-    }
-
-    if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
-        EGC_LOGE("doGLFenceWait: invalid current EGLContext");
-        return INVALID_OPERATION;
-    }
-
-    if (st.mCurrentFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync() &&
-            SyncFeatures::getInstance().useNativeFenceSync()) {
-            // Create an EGLSyncKHR from the current fence.
-            int fenceFd = st.mCurrentFence->dup();
-            if (fenceFd == -1) {
-                EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
-                return -errno;
-            }
-            EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
-            EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
-            if (sync == EGL_NO_SYNC_KHR) {
-                close(fenceFd);
-                EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError());
-                return UNKNOWN_ERROR;
-            }
-
-            // XXX: The spec draft is inconsistent as to whether this should
-            // return an EGLint or void.  Ignore the return value for now, as
-            // it's not strictly needed.
-            eglWaitSyncKHR(dpy, sync, 0);
-            EGLint eglErr = eglGetError();
-            eglDestroySyncKHR(dpy, sync);
-            if (eglErr != EGL_SUCCESS) {
-                EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr);
-                return UNKNOWN_ERROR;
-            }
-        } else {
-            status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked");
-            if (err != NO_ERROR) {
-                EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err);
-                return err;
-            }
-        }
-    }
-
-    return NO_ERROR;
-}
-
-void EGLConsumer::onFreeBufferLocked(int slotIndex) {
-    mEglSlots[slotIndex].mEglImage.clear();
-}
-
-void EGLConsumer::onAbandonLocked() {
-    mCurrentTextureImage.clear();
-}
-
-EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer)
-        : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {}
-
-EGLConsumer::EglImage::~EglImage() {
-    if (mEglImage != EGL_NO_IMAGE_KHR) {
-        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
-            ALOGE("~EglImage: eglDestroyImageKHR failed");
-        }
-        eglTerminate(mEglDisplay);
-    }
-}
-
-status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) {
-    // If there's an image and it's no longer valid, destroy it.
-    bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
-    bool displayInvalid = mEglDisplay != eglDisplay;
-    if (haveImage && (displayInvalid || forceCreation)) {
-        if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
-            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
-        }
-        eglTerminate(mEglDisplay);
-        mEglImage = EGL_NO_IMAGE_KHR;
-        mEglDisplay = EGL_NO_DISPLAY;
-    }
-
-    // If there's no image, create one.
-    if (mEglImage == EGL_NO_IMAGE_KHR) {
-        mEglDisplay = eglDisplay;
-        mEglImage = createImage(mEglDisplay, mGraphicBuffer);
-    }
-
-    // Fail if we can't create a valid image.
-    if (mEglImage == EGL_NO_IMAGE_KHR) {
-        mEglDisplay = EGL_NO_DISPLAY;
-        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
-              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
-              buffer->getPixelFormat());
-        return UNKNOWN_ERROR;
-    }
-
-    return OK;
-}
-
-void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) {
-    glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage));
-}
-
-EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy,
-                                               const sp<GraphicBuffer>& graphicBuffer) {
-    EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
-    const bool createProtectedImage =
-            (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent();
-    EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,
-            EGL_TRUE,
-            createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
-            createProtectedImage ? EGL_TRUE : EGL_NONE,
-            EGL_NONE,
-    };
-    eglInitialize(dpy, nullptr, nullptr);
-    EGLImageKHR image =
-            eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
-    if (image == EGL_NO_IMAGE_KHR) {
-        EGLint error = eglGetError();
-        ALOGE("error creating EGLImage: %#x", error);
-        eglTerminate(dpy);
-    }
-    return image;
-}
-
-}  // namespace android
diff --git a/libs/hwui/surfacetexture/EGLConsumer.h b/libs/hwui/surfacetexture/EGLConsumer.h
deleted file mode 100644
index 7dac3ef..0000000
--- a/libs/hwui/surfacetexture/EGLConsumer.h
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include <gui/BufferQueueDefs.h>
-
-#include <ui/FenceTime.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Mutex.h>
-
-namespace android {
-
-class SurfaceTexture;
-
-/*
- * EGLConsumer implements the parts of SurfaceTexture that deal with
- * textures attached to an GL context.
- */
-class EGLConsumer {
-public:
-    EGLConsumer();
-
-    /**
-     * updateTexImage acquires the most recently queued buffer, and sets the
-     * image contents of the target texture to it.
-     *
-     * This call may only be made while the OpenGL ES context to which the
-     * target texture belongs is bound to the calling thread.
-     *
-     * This calls doGLFenceWait to ensure proper synchronization.
-     */
-    status_t updateTexImage(SurfaceTexture& st);
-
-    /*
-     * releaseTexImage releases the texture acquired in updateTexImage().
-     * This is intended to be used in single buffer mode.
-     *
-     * This call may only be made while the OpenGL ES context to which the
-     * target texture belongs is bound to the calling thread.
-     */
-    status_t releaseTexImage(SurfaceTexture& st);
-
-    /**
-     * detachFromContext detaches the EGLConsumer from the calling thread's
-     * current OpenGL ES context.  This context must be the same as the context
-     * that was current for previous calls to updateTexImage.
-     *
-     * Detaching a EGLConsumer from an OpenGL ES context will result in the
-     * deletion of the OpenGL ES texture object into which the images were being
-     * streamed.  After a EGLConsumer has been detached from the OpenGL ES
-     * context calls to updateTexImage will fail returning INVALID_OPERATION
-     * until the EGLConsumer is attached to a new OpenGL ES context using the
-     * attachToContext method.
-     */
-    status_t detachFromContext(SurfaceTexture& st);
-
-    /**
-     * attachToContext attaches a EGLConsumer that is currently in the
-     * 'detached' state to the current OpenGL ES context.  A EGLConsumer is
-     * in the 'detached' state iff detachFromContext has successfully been
-     * called and no calls to attachToContext have succeeded since the last
-     * detachFromContext call.  Calls to attachToContext made on a
-     * EGLConsumer that is not in the 'detached' state will result in an
-     * INVALID_OPERATION error.
-     *
-     * The tex argument specifies the OpenGL ES texture object name in the
-     * new context into which the image contents will be streamed.  A successful
-     * call to attachToContext will result in this texture object being bound to
-     * the texture target and populated with the image contents that were
-     * current at the time of the last call to detachFromContext.
-     */
-    status_t attachToContext(uint32_t tex, SurfaceTexture& st);
-
-    /**
-     * onAcquireBufferLocked amends the ConsumerBase method to update the
-     * mEglSlots array in addition to the ConsumerBase behavior.
-     */
-    void onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st);
-
-    /**
-     * onReleaseBufferLocked amends the ConsumerBase method to update the
-     * mEglSlots array in addition to the ConsumerBase.
-     */
-    void onReleaseBufferLocked(int slot);
-
-    /**
-     * onFreeBufferLocked frees up the given buffer slot. If the slot has been
-     * initialized this will release the reference to the GraphicBuffer in that
-     * slot and destroy the EGLImage in that slot.  Otherwise it has no effect.
-     */
-    void onFreeBufferLocked(int slotIndex);
-
-    /**
-     * onAbandonLocked amends the ConsumerBase method to clear
-     * mCurrentTextureImage in addition to the ConsumerBase behavior.
-     */
-    void onAbandonLocked();
-
-protected:
-    struct PendingRelease {
-        PendingRelease()
-                : isPending(false)
-                , currentTexture(-1)
-                , graphicBuffer()
-                , display(nullptr)
-                , fence(nullptr) {}
-
-        bool isPending;
-        int currentTexture;
-        sp<GraphicBuffer> graphicBuffer;
-        EGLDisplay display;
-        EGLSyncKHR fence;
-    };
-
-    /**
-     * This releases the buffer in the slot referenced by mCurrentTexture,
-     * then updates state to refer to the BufferItem, which must be a
-     * newly-acquired buffer. If pendingRelease is not null, the parameters
-     * which would have been passed to releaseBufferLocked upon the successful
-     * completion of the method will instead be returned to the caller, so that
-     * it may call releaseBufferLocked itself later.
-     */
-    status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease,
-                                    SurfaceTexture& st);
-
-    /**
-     * Binds mTexName and the current buffer to mTexTarget.  Uses
-     * mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
-     * bind succeeds, this calls doGLFenceWait.
-     */
-    status_t bindTextureImageLocked(SurfaceTexture& st);
-
-    /**
-     * Gets the current EGLDisplay and EGLContext values, and compares them
-     * to mEglDisplay and mEglContext.  If the fields have been previously
-     * set, the values must match; if not, the fields are set to the current
-     * values.
-     * The contextCheck argument is used to ensure that a GL context is
-     * properly set; when set to false, the check is not performed.
-     */
-    status_t checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck = false);
-
-    /**
-     * EglImage is a utility class for tracking and creating EGLImageKHRs. There
-     * is primarily just one image per slot, but there is also special cases:
-     *  - For releaseTexImage, we use a debug image (mReleasedTexImage)
-     *  - After freeBuffer, we must still keep the current image/buffer
-     * Reference counting EGLImages lets us handle all these cases easily while
-     * also only creating new EGLImages from buffers when required.
-     */
-    class EglImage : public LightRefBase<EglImage> {
-    public:
-        EglImage(sp<GraphicBuffer> graphicBuffer);
-
-        /**
-         * createIfNeeded creates an EGLImage if required (we haven't created
-         * one yet, or the EGLDisplay or crop-rect has changed).
-         */
-        status_t createIfNeeded(EGLDisplay display, bool forceCreate = false);
-
-        /**
-         * This calls glEGLImageTargetTexture2DOES to bind the image to the
-         * texture in the specified texture target.
-         */
-        void bindToTextureTarget(uint32_t texTarget);
-
-        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
-        const native_handle* graphicBufferHandle() {
-            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
-        }
-
-    private:
-        // Only allow instantiation using ref counting.
-        friend class LightRefBase<EglImage>;
-        virtual ~EglImage();
-
-        // createImage creates a new EGLImage from a GraphicBuffer.
-        EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer);
-
-        // Disallow copying
-        EglImage(const EglImage& rhs);
-        void operator=(const EglImage& rhs);
-
-        // mGraphicBuffer is the buffer that was used to create this image.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mEglImage is the EGLImage created from mGraphicBuffer.
-        EGLImageKHR mEglImage;
-
-        // mEGLDisplay is the EGLDisplay that was used to create mEglImage.
-        EGLDisplay mEglDisplay;
-
-        // mCropRect is the crop rectangle passed to EGL when mEglImage
-        // was created.
-        Rect mCropRect;
-    };
-
-    /**
-     * doGLFenceWaitLocked inserts a wait command into the OpenGL ES command
-     * stream to ensure that it is safe for future OpenGL ES commands to
-     * access the current texture buffer.
-     */
-    status_t doGLFenceWaitLocked(SurfaceTexture& st) const;
-
-    /**
-     * syncForReleaseLocked performs the synchronization needed to release the
-     * current slot from an OpenGL ES context.  If needed it will set the
-     * current slot's fence to guard against a producer accessing the buffer
-     * before the outstanding accesses have completed.
-     */
-    status_t syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st);
-
-    /**
-     * returns a graphic buffer used when the texture image has been released
-     */
-    static sp<GraphicBuffer> getDebugTexImageBuffer();
-
-    /**
-     * The default consumer usage flags that EGLConsumer always sets on its
-     * BufferQueue instance; these will be OR:d with any additional flags passed
-     * from the EGLConsumer user. In particular, EGLConsumer will always
-     * consume buffers as hardware textures.
-     */
-    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
-
-    /**
-     * mCurrentTextureImage is the EglImage/buffer of the current texture. It's
-     * possible that this buffer is not associated with any buffer slot, so we
-     * must track it separately in order to support the getCurrentBuffer method.
-     */
-    sp<EglImage> mCurrentTextureImage;
-
-    /**
-     * EGLSlot contains the information and object references that
-     * EGLConsumer maintains about a BufferQueue buffer slot.
-     */
-    struct EglSlot {
-        EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {}
-
-        /**
-         * mEglImage is the EGLImage created from mGraphicBuffer.
-         */
-        sp<EglImage> mEglImage;
-
-        /**
-         * mFence is the EGL sync object that must signal before the buffer
-         * associated with this buffer slot may be dequeued. It is initialized
-         * to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
-         * on a compile-time option) set to a new sync object in updateTexImage.
-         */
-        EGLSyncKHR mEglFence;
-    };
-
-    /**
-     * mEglDisplay is the EGLDisplay with which this EGLConsumer is currently
-     * associated.  It is intialized to EGL_NO_DISPLAY and gets set to the
-     * current display when updateTexImage is called for the first time and when
-     * attachToContext is called.
-     */
-    EGLDisplay mEglDisplay;
-
-    /**
-     * mEglContext is the OpenGL ES context with which this EGLConsumer is
-     * currently associated.  It is initialized to EGL_NO_CONTEXT and gets set
-     * to the current GL context when updateTexImage is called for the first
-     * time and when attachToContext is called.
-     */
-    EGLContext mEglContext;
-
-    /**
-     * mEGLSlots stores the buffers that have been allocated by the BufferQueue
-     * for each buffer slot.  It is initialized to null pointers, and gets
-     * filled in with the result of BufferQueue::acquire when the
-     * client dequeues a buffer from a
-     * slot that has not yet been used. The buffer allocated to a slot will also
-     * be replaced if the requested buffer usage or geometry differs from that
-     * of the buffer allocated to a slot.
-     */
-    EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
-
-    /**
-     * protects static initialization
-     */
-    static Mutex sStaticInitLock;
-
-    /**
-     * mReleasedTexImageBuffer is a dummy buffer used when in single buffer
-     * mode and releaseTexImage() has been called
-     */
-    static sp<GraphicBuffer> sReleasedTexImageBuffer;
-    sp<EglImage> mReleasedTexImage;
-};
-
-}  // namespace android
diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp
deleted file mode 100644
index 17ee17d..0000000
--- a/libs/hwui/surfacetexture/ImageConsumer.cpp
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ImageConsumer.h"
-#include <gui/BufferQueue.h>
-#include "Properties.h"
-#include "SurfaceTexture.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/RenderThread.h"
-#include "renderthread/VulkanManager.h"
-#include "utils/Color.h"
-#include <GrAHardwareBufferUtils.h>
-#include <GrBackendSurface.h>
-
-// Macro for including the SurfaceTexture name in log messages
-#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__)
-
-using namespace android::uirenderer::renderthread;
-
-namespace android {
-
-void ImageConsumer::onFreeBufferLocked(int slotIndex) {
-    // This callback may be invoked on any thread.
-    mImageSlots[slotIndex].clear();
-}
-
-void ImageConsumer::onAcquireBufferLocked(BufferItem* item) {
-    // If item->mGraphicBuffer is not null, this buffer has not been acquired
-    // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage.
-    if (item->mGraphicBuffer != nullptr) {
-        mImageSlots[item->mSlot].clear();
-    }
-}
-
-void ImageConsumer::onReleaseBufferLocked(int buf) {
-    mImageSlots[buf].eglFence() = EGL_NO_SYNC_KHR;
-}
-
-/**
- * AutoBackendTextureRelease manages EglImage/VkImage lifetime. It is a ref-counted object
- * that keeps GPU resources alive until the last SKImage object using them is destroyed.
- */
-class AutoBackendTextureRelease {
-public:
-    static void releaseProc(SkImage::ReleaseContext releaseContext);
-
-    AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer);
-
-    const GrBackendTexture& getTexture() const { return mBackendTexture; }
-
-    void ref() { mUsageCount++; }
-
-    void unref(bool releaseImage);
-
-    inline sk_sp<SkImage> getImage() { return mImage; }
-
-    void makeImage(sp<GraphicBuffer>& graphicBuffer, android_dataspace dataspace,
-                   GrContext* context);
-
-    void newBufferContent(GrContext* context);
-
-private:
-    // The only way to invoke dtor is with unref, when mUsageCount is 0.
-    ~AutoBackendTextureRelease() {}
-
-    GrBackendTexture mBackendTexture;
-    GrAHardwareBufferUtils::DeleteImageProc mDeleteProc;
-    GrAHardwareBufferUtils::UpdateImageProc mUpdateProc;
-    GrAHardwareBufferUtils::TexImageCtx mImageCtx;
-
-    // Starting with refcount 1, because the first ref is held by SurfaceTexture. Additional refs
-    // are held by SkImages.
-    int mUsageCount = 1;
-
-    // mImage is the SkImage created from mBackendTexture.
-    sk_sp<SkImage> mImage;
-};
-
-AutoBackendTextureRelease::AutoBackendTextureRelease(GrContext* context, GraphicBuffer* buffer) {
-    bool createProtectedImage =
-        0 != (buffer->getUsage() & GraphicBuffer::USAGE_PROTECTED);
-    GrBackendFormat backendFormat = GrAHardwareBufferUtils::GetBackendFormat(
-        context,
-        reinterpret_cast<AHardwareBuffer*>(buffer),
-        buffer->getPixelFormat(),
-        false);
-    mBackendTexture = GrAHardwareBufferUtils::MakeBackendTexture(
-        context,
-        reinterpret_cast<AHardwareBuffer*>(buffer),
-        buffer->getWidth(),
-        buffer->getHeight(),
-        &mDeleteProc,
-        &mUpdateProc,
-        &mImageCtx,
-        createProtectedImage,
-        backendFormat,
-        false);
-}
-
-void AutoBackendTextureRelease::unref(bool releaseImage) {
-    if (!RenderThread::isCurrent()) {
-        // EGLImage needs to be destroyed on RenderThread to prevent memory leak.
-        // ~SkImage dtor for both pipelines needs to be invoked on RenderThread, because it is not
-        // thread safe.
-        RenderThread::getInstance().queue().post([this, releaseImage]() { unref(releaseImage); });
-        return;
-    }
-
-    if (releaseImage) {
-        mImage.reset();
-    }
-
-    mUsageCount--;
-    if (mUsageCount <= 0) {
-        if (mBackendTexture.isValid()) {
-            mDeleteProc(mImageCtx);
-            mBackendTexture = {};
-        }
-        delete this;
-    }
-}
-
-void AutoBackendTextureRelease::releaseProc(SkImage::ReleaseContext releaseContext) {
-    AutoBackendTextureRelease* textureRelease =
-        reinterpret_cast<AutoBackendTextureRelease*>(releaseContext);
-    textureRelease->unref(false);
-}
-
-void AutoBackendTextureRelease::makeImage(sp<GraphicBuffer>& graphicBuffer,
-                                          android_dataspace dataspace, GrContext* context) {
-    SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(
-        graphicBuffer->getPixelFormat());
-    mImage = SkImage::MakeFromTexture(context,
-        mBackendTexture,
-        kTopLeft_GrSurfaceOrigin,
-        colorType,
-        kPremul_SkAlphaType,
-        uirenderer::DataSpaceToColorSpace(dataspace),
-        releaseProc,
-        this);
-    if (mImage.get()) {
-        // The following ref will be counteracted by releaseProc, when SkImage is discarded.
-        ref();
-    }
-}
-
-void AutoBackendTextureRelease::newBufferContent(GrContext* context) {
-    if (mBackendTexture.isValid()) {
-        mUpdateProc(mImageCtx, context);
-    }
-}
-
-void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer,
-                                              android_dataspace dataspace, bool forceCreate,
-                                              GrContext* context) {
-    if (!mTextureRelease || !mTextureRelease->getImage().get() || dataspace != mDataspace
-            || forceCreate) {
-        if (!graphicBuffer.get()) {
-            clear();
-            return;
-        }
-
-        if (!mTextureRelease) {
-            mTextureRelease = new AutoBackendTextureRelease(context, graphicBuffer.get());
-        } else {
-            mTextureRelease->newBufferContent(context);
-        }
-
-        mDataspace = dataspace;
-        mTextureRelease->makeImage(graphicBuffer, dataspace, context);
-    }
-}
-
-void ImageConsumer::ImageSlot::clear() {
-    if (mTextureRelease) {
-        // The following unref counteracts the initial mUsageCount of 1, set by default initializer.
-        mTextureRelease->unref(true);
-        mTextureRelease = nullptr;
-    }
-}
-
-sk_sp<SkImage> ImageConsumer::ImageSlot::getImage() {
-    return mTextureRelease ? mTextureRelease->getImage() : nullptr;
-}
-
-sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st,
-                                           uirenderer::RenderState& renderState) {
-    BufferItem item;
-    status_t err;
-    err = st.acquireBufferLocked(&item, 0);
-    if (err != OK) {
-        if (err != BufferQueue::NO_BUFFER_AVAILABLE) {
-            IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
-        } else {
-            int slot = st.mCurrentTexture;
-            if (slot != BufferItem::INVALID_BUFFER_SLOT) {
-                *queueEmpty = true;
-                mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer,
-                        st.mCurrentDataSpace, false, renderState.getRenderThread().getGrContext());
-                return mImageSlots[slot].getImage();
-            }
-        }
-        return nullptr;
-    }
-
-    int slot = item.mSlot;
-    if (item.mFence->isValid()) {
-        // Wait on the producer fence for the buffer to be ready.
-        if (uirenderer::Properties::getRenderPipelineType() ==
-            uirenderer::RenderPipelineType::SkiaGL) {
-            err = renderState.getRenderThread().eglManager().fenceWait(item.mFence);
-        } else {
-            err = renderState.getRenderThread().vulkanManager().fenceWait(
-                    item.mFence, renderState.getRenderThread().getGrContext());
-        }
-        if (err != OK) {
-            st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
-                                   EGL_NO_SYNC_KHR);
-            return nullptr;
-        }
-    }
-
-    // Release old buffer.
-    if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) {
-        // If needed, set the released slot's fence to guard against a producer accessing the
-        // buffer before the outstanding accesses have completed.
-        sp<Fence> releaseFence;
-        EGLDisplay display = EGL_NO_DISPLAY;
-        if (uirenderer::Properties::getRenderPipelineType() ==
-            uirenderer::RenderPipelineType::SkiaGL) {
-            auto& eglManager = renderState.getRenderThread().eglManager();
-            display = eglManager.eglDisplay();
-            err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].eglFence(),
-                                                releaseFence);
-        } else {
-            err = renderState.getRenderThread().vulkanManager().createReleaseFence(
-                    releaseFence, renderState.getRenderThread().getGrContext());
-        }
-        if (OK != err) {
-            st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
-                                   EGL_NO_SYNC_KHR);
-            return nullptr;
-        }
-
-        if (releaseFence.get()) {
-            status_t err = st.addReleaseFenceLocked(
-                    st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, releaseFence);
-            if (err != OK) {
-                IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err);
-                st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY,
-                                       EGL_NO_SYNC_KHR);
-                return nullptr;
-            }
-        }
-
-        // Finally release the old buffer.
-        status_t status = st.releaseBufferLocked(
-                st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display,
-                mImageSlots[st.mCurrentTexture].eglFence());
-        if (status < NO_ERROR) {
-            IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status);
-            err = status;
-            // Keep going, with error raised.
-        }
-    }
-
-    // Update the state.
-    st.mCurrentTexture = slot;
-    st.mCurrentCrop = item.mCrop;
-    st.mCurrentTransform = item.mTransform;
-    st.mCurrentScalingMode = item.mScalingMode;
-    st.mCurrentTimestamp = item.mTimestamp;
-    st.mCurrentDataSpace = item.mDataSpace;
-    st.mCurrentFence = item.mFence;
-    st.mCurrentFenceTime = item.mFenceTime;
-    st.mCurrentFrameNumber = item.mFrameNumber;
-    st.computeCurrentTransformMatrixLocked();
-
-    *queueEmpty = false;
-    mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer, item.mDataSpace, true,
-        renderState.getRenderThread().getGrContext());
-    return mImageSlots[slot].getImage();
-}
-
-} /* namespace android */
diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h
deleted file mode 100644
index 3e2a91a..0000000
--- a/libs/hwui/surfacetexture/ImageConsumer.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include <gui/BufferQueueDefs.h>
-
-#include <SkImage.h>
-#include <cutils/compiler.h>
-#include <gui/BufferItem.h>
-#include <system/graphics.h>
-
-namespace android {
-
-namespace uirenderer {
-class RenderState;
-}
-
-class AutoBackendTextureRelease;
-class SurfaceTexture;
-
-/*
- * ImageConsumer implements the parts of SurfaceTexture that deal with
- * images consumed by HWUI view system.
- */
-class ImageConsumer {
-public:
-    sk_sp<SkImage> dequeueImage(bool* queueEmpty, SurfaceTexture& cb,
-                                uirenderer::RenderState& renderState);
-
-    /**
-     * onAcquireBufferLocked amends the ConsumerBase method to update the
-     * mImageSlots array in addition to the ConsumerBase behavior.
-     */
-    void onAcquireBufferLocked(BufferItem* item);
-
-    /**
-     * onReleaseBufferLocked amends the ConsumerBase method to update the
-     * mImageSlots array in addition to the ConsumerBase.
-     */
-    void onReleaseBufferLocked(int slot);
-
-    /**
-     * onFreeBufferLocked frees up the given buffer slot. If the slot has been
-     * initialized this will release the reference to the GraphicBuffer in that
-     * slot and destroy the SkImage in that slot. Otherwise it has no effect.
-     */
-    void onFreeBufferLocked(int slotIndex);
-
-private:
-    /**
-     * ImageSlot contains the information and object references that
-     * ImageConsumer maintains about a BufferQueue buffer slot.
-     */
-    class ImageSlot {
-    public:
-        ImageSlot() : mDataspace(HAL_DATASPACE_UNKNOWN), mEglFence(EGL_NO_SYNC_KHR) {}
-
-        ~ImageSlot() { clear(); }
-
-        void createIfNeeded(sp<GraphicBuffer> graphicBuffer, android_dataspace dataspace,
-                            bool forceCreate, GrContext* context);
-
-        void clear();
-
-        inline EGLSyncKHR& eglFence() { return mEglFence; }
-
-        sk_sp<SkImage> getImage();
-
-    private:
-        // the dataspace associated with the current image
-        android_dataspace mDataspace;
-
-        /**
-         * mEglFence is the EGL sync object that must signal before the buffer
-         * associated with this buffer slot may be dequeued.
-         */
-        EGLSyncKHR mEglFence;
-
-        /**
-         * mTextureRelease may outlive ImageConsumer, if the last ref is held by an SkImage.
-         * ImageConsumer holds one ref to mTextureRelease, which is decremented by "clear".
-         */
-        AutoBackendTextureRelease* mTextureRelease = nullptr;
-    };
-
-    /**
-     * ImageConsumer stores the SkImages that have been allocated by the BufferQueue
-     * for each buffer slot.  It is initialized to null pointers, and gets
-     * filled in with the result of BufferQueue::acquire when the
-     * client dequeues a buffer from a
-     * slot that has not yet been used. The buffer allocated to a slot will also
-     * be replaced if the requested buffer usage or geometry differs from that
-     * of the buffer allocated to a slot.
-     */
-    ImageSlot mImageSlots[BufferQueueDefs::NUM_BUFFER_SLOTS];
-};
-
-} /* namespace android */
diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp
deleted file mode 100644
index a27db65..0000000
--- a/libs/hwui/surfacetexture/SurfaceTexture.cpp
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cutils/compiler.h>
-#include <gui/BufferQueue.h>
-#include <math/mat4.h>
-#include <system/window.h>
-
-#include <utils/Trace.h>
-
-#include "Matrix.h"
-#include "SurfaceTexture.h"
-#include "ImageConsumer.h"
-
-namespace android {
-
-// Macros for including the SurfaceTexture name in log messages
-#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
-#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
-
-static const mat4 mtxIdentity;
-
-SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
-                               uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
-        : ConsumerBase(bq, isControlledByApp)
-        , mCurrentCrop(Rect::EMPTY_RECT)
-        , mCurrentTransform(0)
-        , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE)
-        , mCurrentFence(Fence::NO_FENCE)
-        , mCurrentTimestamp(0)
-        , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN)
-        , mCurrentFrameNumber(0)
-        , mDefaultWidth(1)
-        , mDefaultHeight(1)
-        , mFilteringEnabled(true)
-        , mTexName(tex)
-        , mUseFenceSync(useFenceSync)
-        , mTexTarget(texTarget)
-        , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
-        , mOpMode(OpMode::attachedToGL) {
-    SFT_LOGV("SurfaceTexture");
-
-    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
-
-    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
-}
-
-SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
-                               bool useFenceSync, bool isControlledByApp)
-        : ConsumerBase(bq, isControlledByApp)
-        , mCurrentCrop(Rect::EMPTY_RECT)
-        , mCurrentTransform(0)
-        , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE)
-        , mCurrentFence(Fence::NO_FENCE)
-        , mCurrentTimestamp(0)
-        , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN)
-        , mCurrentFrameNumber(0)
-        , mDefaultWidth(1)
-        , mDefaultHeight(1)
-        , mFilteringEnabled(true)
-        , mTexName(0)
-        , mUseFenceSync(useFenceSync)
-        , mTexTarget(texTarget)
-        , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
-        , mOpMode(OpMode::detached) {
-    SFT_LOGV("SurfaceTexture");
-
-    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
-
-    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
-}
-
-status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        SFT_LOGE("setDefaultBufferSize: SurfaceTexture is abandoned!");
-        return NO_INIT;
-    }
-    mDefaultWidth = w;
-    mDefaultHeight = h;
-    return mConsumer->setDefaultBufferSize(w, h);
-}
-
-status_t SurfaceTexture::updateTexImage() {
-    ATRACE_CALL();
-    SFT_LOGV("updateTexImage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("updateTexImage: SurfaceTexture is abandoned!");
-        return NO_INIT;
-    }
-
-    return mEGLConsumer.updateTexImage(*this);
-}
-
-status_t SurfaceTexture::releaseTexImage() {
-    // releaseTexImage can be invoked even when not attached to a GL context.
-    ATRACE_CALL();
-    SFT_LOGV("releaseTexImage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("releaseTexImage: SurfaceTexture is abandoned!");
-        return NO_INIT;
-    }
-
-    return mEGLConsumer.releaseTexImage(*this);
-}
-
-status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
-                                             uint64_t maxFrameNumber) {
-    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    switch (mOpMode) {
-        case OpMode::attachedToView:
-            mImageConsumer.onAcquireBufferLocked(item);
-            break;
-        case OpMode::attachedToGL:
-            mEGLConsumer.onAcquireBufferLocked(item, *this);
-            break;
-        case OpMode::detached:
-            break;
-    }
-
-    return NO_ERROR;
-}
-
-status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer,
-                                             EGLDisplay display, EGLSyncKHR eglFence) {
-    // release the buffer if it hasn't already been discarded by the
-    // BufferQueue. This can happen, for example, when the producer of this
-    // buffer has reallocated the original buffer slot after this buffer
-    // was acquired.
-    status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence);
-    // We could be releasing an EGL/Vulkan buffer, even if not currently attached to a GL context.
-    mImageConsumer.onReleaseBufferLocked(buf);
-    mEGLConsumer.onReleaseBufferLocked(buf);
-    return err;
-}
-
-status_t SurfaceTexture::detachFromContext() {
-    ATRACE_CALL();
-    SFT_LOGV("detachFromContext");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("detachFromContext: abandoned SurfaceTexture");
-        return NO_INIT;
-    }
-
-    if (mOpMode != OpMode::attachedToGL) {
-        SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context");
-        return INVALID_OPERATION;
-    }
-
-    status_t err = mEGLConsumer.detachFromContext(*this);
-    if (err == OK) {
-        mOpMode = OpMode::detached;
-    }
-
-    return err;
-}
-
-status_t SurfaceTexture::attachToContext(uint32_t tex) {
-    ATRACE_CALL();
-    SFT_LOGV("attachToContext");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("attachToContext: abandoned SurfaceTexture");
-        return NO_INIT;
-    }
-
-    if (mOpMode != OpMode::detached) {
-        SFT_LOGE(
-                "attachToContext: SurfaceTexture is already attached to a "
-                "context");
-        return INVALID_OPERATION;
-    }
-
-    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        // release possible ImageConsumer cache
-        mImageConsumer.onFreeBufferLocked(mCurrentTexture);
-    }
-
-    return mEGLConsumer.attachToContext(tex, *this);
-}
-
-void SurfaceTexture::attachToView() {
-    ATRACE_CALL();
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        SFT_LOGE("attachToView: abandoned SurfaceTexture");
-        return;
-    }
-    if (mOpMode == OpMode::detached) {
-        mOpMode = OpMode::attachedToView;
-
-        if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-            // release possible EGLConsumer texture cache
-            mEGLConsumer.onFreeBufferLocked(mCurrentTexture);
-            mEGLConsumer.onAbandonLocked();
-        }
-    } else {
-        SFT_LOGE("attachToView: already attached");
-    }
-}
-
-void SurfaceTexture::detachFromView() {
-    ATRACE_CALL();
-    Mutex::Autolock _l(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("detachFromView: abandoned SurfaceTexture");
-        return;
-    }
-
-    if (mOpMode == OpMode::attachedToView) {
-        mOpMode = OpMode::detached;
-        // Free all EglImage and VkImage before the context is destroyed.
-        for (int i=0; i < BufferQueueDefs::NUM_BUFFER_SLOTS; i++) {
-            mImageConsumer.onFreeBufferLocked(i);
-        }
-    } else {
-        SFT_LOGE("detachFromView: not attached to View");
-    }
-}
-
-uint32_t SurfaceTexture::getCurrentTextureTarget() const {
-    return mTexTarget;
-}
-
-void SurfaceTexture::getTransformMatrix(float mtx[16]) {
-    Mutex::Autolock lock(mMutex);
-    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
-}
-
-void SurfaceTexture::setFilteringEnabled(bool enabled) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!");
-        return;
-    }
-    bool needsRecompute = mFilteringEnabled != enabled;
-    mFilteringEnabled = enabled;
-
-    if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) {
-        SFT_LOGD("setFilteringEnabled called with no current item");
-    }
-
-    if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        computeCurrentTransformMatrixLocked();
-    }
-}
-
-void SurfaceTexture::computeCurrentTransformMatrixLocked() {
-    SFT_LOGV("computeCurrentTransformMatrixLocked");
-    sp<GraphicBuffer> buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
-                                    ? nullptr
-                                    : mSlots[mCurrentTexture].mGraphicBuffer;
-    if (buf == nullptr) {
-        SFT_LOGD("computeCurrentTransformMatrixLocked: no current item");
-    }
-    computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform,
-                           mFilteringEnabled);
-}
-
-void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf,
-                                            const Rect& cropRect, uint32_t transform,
-                                            bool filtering) {
-    // Transform matrices
-    static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-    static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
-    static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-
-    mat4 xform;
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        xform *= mtxFlipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        xform *= mtxFlipV;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        xform *= mtxRot90;
-    }
-
-    if (!cropRect.isEmpty() && buf.get()) {
-        float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
-        float bufferWidth = buf->getWidth();
-        float bufferHeight = buf->getHeight();
-        float shrinkAmount = 0.0f;
-        if (filtering) {
-            // In order to prevent bilinear sampling beyond the edge of the
-            // crop rectangle we may need to shrink it by 2 texels in each
-            // dimension.  Normally this would just need to take 1/2 a texel
-            // off each end, but because the chroma channels of YUV420 images
-            // are subsampled we may need to shrink the crop region by a whole
-            // texel on each side.
-            switch (buf->getPixelFormat()) {
-                case PIXEL_FORMAT_RGBA_8888:
-                case PIXEL_FORMAT_RGBX_8888:
-                case PIXEL_FORMAT_RGBA_FP16:
-                case PIXEL_FORMAT_RGBA_1010102:
-                case PIXEL_FORMAT_RGB_888:
-                case PIXEL_FORMAT_RGB_565:
-                case PIXEL_FORMAT_BGRA_8888:
-                    // We know there's no subsampling of any channels, so we
-                    // only need to shrink by a half a pixel.
-                    shrinkAmount = 0.5;
-                    break;
-
-                default:
-                    // If we don't recognize the format, we must assume the
-                    // worst case (that we care about), which is YUV420.
-                    shrinkAmount = 1.0;
-                    break;
-            }
-        }
-
-        // Only shrink the dimensions that are not the size of the buffer.
-        if (cropRect.width() < bufferWidth) {
-            tx = (float(cropRect.left) + shrinkAmount) / bufferWidth;
-            sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth;
-        }
-        if (cropRect.height() < bufferHeight) {
-            ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight;
-            sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight;
-        }
-
-        mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1);
-        xform = crop * xform;
-    }
-
-    // SurfaceFlinger expects the top of its window textures to be at a Y
-    // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
-    // want to expose this to applications, however, so we must add an
-    // additional vertical flip to the transform after all the other transforms.
-    xform = mtxFlipV * xform;
-
-    memcpy(outTransform, xform.asArray(), sizeof(xform));
-}
-
-Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
-    Rect outCrop = crop;
-
-    uint32_t newWidth = static_cast<uint32_t>(crop.width());
-    uint32_t newHeight = static_cast<uint32_t>(crop.height());
-
-    if (newWidth * bufferHeight > newHeight * bufferWidth) {
-        newWidth = newHeight * bufferWidth / bufferHeight;
-        ALOGV("too wide: newWidth = %d", newWidth);
-    } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
-        newHeight = newWidth * bufferHeight / bufferWidth;
-        ALOGV("too tall: newHeight = %d", newHeight);
-    }
-
-    uint32_t currentWidth = static_cast<uint32_t>(crop.width());
-    uint32_t currentHeight = static_cast<uint32_t>(crop.height());
-
-    // The crop is too wide
-    if (newWidth < currentWidth) {
-        uint32_t dw = currentWidth - newWidth;
-        auto halfdw = dw / 2;
-        outCrop.left += halfdw;
-        // Not halfdw because it would subtract 1 too few when dw is odd
-        outCrop.right -= (dw - halfdw);
-        // The crop is too tall
-    } else if (newHeight < currentHeight) {
-        uint32_t dh = currentHeight - newHeight;
-        auto halfdh = dh / 2;
-        outCrop.top += halfdh;
-        // Not halfdh because it would subtract 1 too few when dh is odd
-        outCrop.bottom -= (dh - halfdh);
-    }
-
-    ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right,
-          outCrop.bottom);
-
-    return outCrop;
-}
-
-nsecs_t SurfaceTexture::getTimestamp() {
-    SFT_LOGV("getTimestamp");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTimestamp;
-}
-
-android_dataspace SurfaceTexture::getCurrentDataSpace() {
-    SFT_LOGV("getCurrentDataSpace");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentDataSpace;
-}
-
-uint64_t SurfaceTexture::getFrameNumber() {
-    SFT_LOGV("getFrameNumber");
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFrameNumber;
-}
-
-Rect SurfaceTexture::getCurrentCrop() const {
-    Mutex::Autolock lock(mMutex);
-    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
-                   ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
-                   : mCurrentCrop;
-}
-
-uint32_t SurfaceTexture::getCurrentTransform() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentTransform;
-}
-
-uint32_t SurfaceTexture::getCurrentScalingMode() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentScalingMode;
-}
-
-sp<Fence> SurfaceTexture::getCurrentFence() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFence;
-}
-
-std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const {
-    Mutex::Autolock lock(mMutex);
-    return mCurrentFenceTime;
-}
-
-void SurfaceTexture::freeBufferLocked(int slotIndex) {
-    SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    if (slotIndex == mCurrentTexture) {
-        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
-    }
-    // The slotIndex buffer could have EGL or SkImage cache, but there is no way to tell for sure.
-    // Buffers can be freed after SurfaceTexture has detached from GL context or View.
-    mImageConsumer.onFreeBufferLocked(slotIndex);
-    mEGLConsumer.onFreeBufferLocked(slotIndex);
-    ConsumerBase::freeBufferLocked(slotIndex);
-}
-
-void SurfaceTexture::abandonLocked() {
-    SFT_LOGV("abandonLocked");
-    mEGLConsumer.onAbandonLocked();
-    ConsumerBase::abandonLocked();
-}
-
-status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) {
-    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
-}
-
-void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const {
-    result.appendFormat(
-            "%smTexName=%d mCurrentTexture=%d\n"
-            "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
-            prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top,
-            mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform);
-
-    ConsumerBase::dumpLocked(result, prefix);
-}
-
-sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty,
-                                            uirenderer::RenderState& renderState) {
-    Mutex::Autolock _l(mMutex);
-
-    if (mAbandoned) {
-        SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!");
-        return nullptr;
-    }
-
-    if (mOpMode != OpMode::attachedToView) {
-        SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View");
-        return nullptr;
-    }
-
-    auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState);
-    if (image.get()) {
-        uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix);
-    }
-    return image;
-}
-
-}  // namespace android
diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h
deleted file mode 100644
index b5d136f..0000000
--- a/libs/hwui/surfacetexture/SurfaceTexture.h
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gui/BufferQueueDefs.h>
-#include <gui/ConsumerBase.h>
-
-#include <ui/FenceTime.h>
-#include <ui/GraphicBuffer.h>
-
-#include <utils/Mutex.h>
-#include <utils/String8.h>
-
-#include "EGLConsumer.h"
-#include "ImageConsumer.h"
-
-namespace android {
-
-namespace uirenderer {
-class RenderState;
-}
-
-/*
- * SurfaceTexture consumes buffers of graphics data from a BufferQueue,
- * and makes them available to HWUI render thread as a SkImage and to
- * an application GL render thread as an OpenGL texture.
- *
- * When attached to an application GL render thread, a typical usage
- * pattern is to set up the SurfaceTexture with the
- * desired options, and call updateTexImage() when a new frame is desired.
- * If a new frame is available, the texture will be updated.  If not,
- * the previous contents are retained.
- *
- * When attached to a HWUI render thread, the TextureView implementation
- * calls dequeueImage, which either pulls a new SkImage or returns the
- * last cached SkImage if BufferQueue is empty.
- * When attached to HWUI render thread, SurfaceTexture is compatible to
- * both Vulkan and GL drawing pipelines.
- */
-class ANDROID_API SurfaceTexture : public ConsumerBase {
-public:
-    enum { TEXTURE_EXTERNAL = 0x8D65 };  // GL_TEXTURE_EXTERNAL_OES
-    typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
-
-    /**
-     * SurfaceTexture constructs a new SurfaceTexture object. If the constructor with
-     * the tex parameter is used, tex indicates the name of the OpenGL ES
-     * texture to which images are to be streamed. texTarget specifies the
-     * OpenGL ES texture target to which the texture will be bound in
-     * updateTexImage. useFenceSync specifies whether fences should be used to
-     * synchronize access to buffers if that behavior is enabled at
-     * compile-time.
-     *
-     * A SurfaceTexture may be detached from one OpenGL ES context and then
-     * attached to a different context using the detachFromContext and
-     * attachToContext methods, respectively. The intention of these methods is
-     * purely to allow a SurfaceTexture to be transferred from one consumer
-     * context to another. If such a transfer is not needed there is no
-     * requirement that either of these methods be called.
-     *
-     * If the constructor with the tex parameter is used, the SurfaceTexture is
-     * created in a state where it is considered attached to an OpenGL ES
-     * context for the purposes of the attachToContext and detachFromContext
-     * methods. However, despite being considered "attached" to a context, the
-     * specific OpenGL ES context doesn't get latched until the first call to
-     * updateTexImage. After that point, all calls to updateTexImage must be
-     * made with the same OpenGL ES context current.
-     *
-     * If the constructor without the tex parameter is used, the SurfaceTexture is
-     * created in a detached state, and attachToContext must be called before
-     * calls to updateTexImage.
-     */
-    SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texureTarget,
-                   bool useFenceSync, bool isControlledByApp);
-
-    SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texureTarget, bool useFenceSync,
-                   bool isControlledByApp);
-
-    /**
-     * updateTexImage acquires the most recently queued buffer, and sets the
-     * image contents of the target texture to it.
-     *
-     * This call may only be made while the OpenGL ES context to which the
-     * target texture belongs is bound to the calling thread.
-     *
-     * This calls doGLFenceWait to ensure proper synchronization.
-     */
-    status_t updateTexImage();
-
-    /**
-     * releaseTexImage releases the texture acquired in updateTexImage().
-     * This is intended to be used in single buffer mode.
-     *
-     * This call may only be made while the OpenGL ES context to which the
-     * target texture belongs is bound to the calling thread.
-     */
-    status_t releaseTexImage();
-
-    /**
-     * getTransformMatrix retrieves the 4x4 texture coordinate transform matrix
-     * associated with the texture image set by the most recent call to
-     * updateTexImage.
-     *
-     * This transform matrix maps 2D homogeneous texture coordinates of the form
-     * (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture
-     * coordinate that should be used to sample that location from the texture.
-     * Sampling the texture outside of the range of this transform is undefined.
-     *
-     * This transform is necessary to compensate for transforms that the stream
-     * content producer may implicitly apply to the content. By forcing users of
-     * a SurfaceTexture to apply this transform we avoid performing an extra
-     * copy of the data that would be needed to hide the transform from the
-     * user.
-     *
-     * The matrix is stored in column-major order so that it may be passed
-     * directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv
-     * functions.
-     */
-    void getTransformMatrix(float mtx[16]);
-
-    /**
-     * Computes the transform matrix documented by getTransformMatrix
-     * from the BufferItem sub parts.
-     */
-    static void computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf,
-                                       const Rect& cropRect, uint32_t transform, bool filtering);
-
-    /**
-     * Scale the crop down horizontally or vertically such that it has the
-     * same aspect ratio as the buffer does.
-     */
-    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
-
-    /**
-     * getTimestamp retrieves the timestamp associated with the texture image
-     * set by the most recent call to updateTexImage.
-     *
-     * The timestamp is in nanoseconds, and is monotonically increasing. Its
-     * other semantics (zero point, etc) are source-dependent and should be
-     * documented by the source.
-     */
-    int64_t getTimestamp();
-
-    /**
-     * getDataSpace retrieves the DataSpace associated with the texture image
-     * set by the most recent call to updateTexImage.
-     */
-    android_dataspace getCurrentDataSpace();
-
-    /**
-     * getFrameNumber retrieves the frame number associated with the texture
-     * image set by the most recent call to updateTexImage.
-     *
-     * The frame number is an incrementing counter set to 0 at the creation of
-     * the BufferQueue associated with this consumer.
-     */
-    uint64_t getFrameNumber();
-
-    /**
-     * setDefaultBufferSize is used to set the size of buffers returned by
-     * requestBuffers when a with and height of zero is requested.
-     * A call to setDefaultBufferSize() may trigger requestBuffers() to
-     * be called from the client.
-     * The width and height parameters must be no greater than the minimum of
-     * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
-     * An error due to invalid dimensions might not be reported until
-     * updateTexImage() is called.
-     */
-    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
-
-    /**
-     * setFilteringEnabled sets whether the transform matrix should be computed
-     * for use with bilinear filtering.
-     */
-    void setFilteringEnabled(bool enabled);
-
-    /**
-     * getCurrentTextureTarget returns the texture target of the current
-     * texture as returned by updateTexImage().
-     */
-    uint32_t getCurrentTextureTarget() const;
-
-    /**
-     * getCurrentCrop returns the cropping rectangle of the current buffer.
-     */
-    Rect getCurrentCrop() const;
-
-    /**
-     * getCurrentTransform returns the transform of the current buffer.
-     */
-    uint32_t getCurrentTransform() const;
-
-    /**
-     * getCurrentScalingMode returns the scaling mode of the current buffer.
-     */
-    uint32_t getCurrentScalingMode() const;
-
-    /**
-     * getCurrentFence returns the fence indicating when the current buffer is
-     * ready to be read from.
-     */
-    sp<Fence> getCurrentFence() const;
-
-    /**
-     * getCurrentFence returns the FenceTime indicating when the current
-     * buffer is ready to be read from.
-     */
-    std::shared_ptr<FenceTime> getCurrentFenceTime() const;
-
-    /**
-     * setConsumerUsageBits overrides the ConsumerBase method to OR
-     * DEFAULT_USAGE_FLAGS to usage.
-     */
-    status_t setConsumerUsageBits(uint64_t usage);
-
-    /**
-     * detachFromContext detaches the SurfaceTexture from the calling thread's
-     * current OpenGL ES context.  This context must be the same as the context
-     * that was current for previous calls to updateTexImage.
-     *
-     * Detaching a SurfaceTexture from an OpenGL ES context will result in the
-     * deletion of the OpenGL ES texture object into which the images were being
-     * streamed.  After a SurfaceTexture has been detached from the OpenGL ES
-     * context calls to updateTexImage will fail returning INVALID_OPERATION
-     * until the SurfaceTexture is attached to a new OpenGL ES context using the
-     * attachToContext method.
-     */
-    status_t detachFromContext();
-
-    /**
-     * attachToContext attaches a SurfaceTexture that is currently in the
-     * 'detached' state to the current OpenGL ES context.  A SurfaceTexture is
-     * in the 'detached' state iff detachFromContext has successfully been
-     * called and no calls to attachToContext have succeeded since the last
-     * detachFromContext call.  Calls to attachToContext made on a
-     * SurfaceTexture that is not in the 'detached' state will result in an
-     * INVALID_OPERATION error.
-     *
-     * The tex argument specifies the OpenGL ES texture object name in the
-     * new context into which the image contents will be streamed.  A successful
-     * call to attachToContext will result in this texture object being bound to
-     * the texture target and populated with the image contents that were
-     * current at the time of the last call to detachFromContext.
-     */
-    status_t attachToContext(uint32_t tex);
-
-    sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, bool* queueEmpty,
-                                uirenderer::RenderState& renderState);
-
-    /**
-     * attachToView attaches a SurfaceTexture that is currently in the
-     * 'detached' state to HWUI View system.
-     */
-    void attachToView();
-
-    /**
-     * detachFromView detaches a SurfaceTexture from HWUI View system.
-     */
-    void detachFromView();
-
-protected:
-    /**
-     * abandonLocked overrides the ConsumerBase method to clear
-     * mCurrentTextureImage in addition to the ConsumerBase behavior.
-     */
-    virtual void abandonLocked();
-
-    /**
-     * dumpLocked overrides the ConsumerBase method to dump SurfaceTexture-
-     * specific info in addition to the ConsumerBase behavior.
-     */
-    virtual void dumpLocked(String8& result, const char* prefix) const override;
-
-    /**
-     * acquireBufferLocked overrides the ConsumerBase method to update the
-     * mEglSlots array in addition to the ConsumerBase behavior.
-     */
-    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
-                                         uint64_t maxFrameNumber = 0) override;
-
-    /**
-     * releaseBufferLocked overrides the ConsumerBase method to update the
-     * mEglSlots array in addition to the ConsumerBase.
-     */
-    virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer,
-                                         EGLDisplay display, EGLSyncKHR eglFence) override;
-
-    /**
-     * freeBufferLocked frees up the given buffer slot. If the slot has been
-     * initialized this will release the reference to the GraphicBuffer in that
-     * slot and destroy the EGLImage in that slot.  Otherwise it has no effect.
-     *
-     * This method must be called with mMutex locked.
-     */
-    virtual void freeBufferLocked(int slotIndex);
-
-    /**
-     * computeCurrentTransformMatrixLocked computes the transform matrix for the
-     * current texture.  It uses mCurrentTransform and the current GraphicBuffer
-     * to compute this matrix and stores it in mCurrentTransformMatrix.
-     * mCurrentTextureImage must not be NULL.
-     */
-    void computeCurrentTransformMatrixLocked();
-
-    /**
-     * The default consumer usage flags that SurfaceTexture always sets on its
-     * BufferQueue instance; these will be OR:d with any additional flags passed
-     * from the SurfaceTexture user. In particular, SurfaceTexture will always
-     * consume buffers as hardware textures.
-     */
-    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
-
-    /**
-     * mCurrentCrop is the crop rectangle that applies to the current texture.
-     * It gets set each time updateTexImage is called.
-     */
-    Rect mCurrentCrop;
-
-    /**
-     * mCurrentTransform is the transform identifier for the current texture. It
-     * gets set each time updateTexImage is called.
-     */
-    uint32_t mCurrentTransform;
-
-    /**
-     * mCurrentScalingMode is the scaling mode for the current texture. It gets
-     * set each time updateTexImage is called.
-     */
-    uint32_t mCurrentScalingMode;
-
-    /**
-     * mCurrentFence is the fence received from BufferQueue in updateTexImage.
-     */
-    sp<Fence> mCurrentFence;
-
-    /**
-     * The FenceTime wrapper around mCurrentFence.
-     */
-    std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
-
-    /**
-     * mCurrentTransformMatrix is the transform matrix for the current texture.
-     * It gets computed by computeTransformMatrix each time updateTexImage is
-     * called.
-     */
-    float mCurrentTransformMatrix[16];
-
-    /**
-     * mCurrentTimestamp is the timestamp for the current texture. It
-     * gets set each time updateTexImage is called.
-     */
-    int64_t mCurrentTimestamp;
-
-    /**
-     * mCurrentDataSpace is the dataspace for the current texture. It
-     * gets set each time updateTexImage is called.
-     */
-    android_dataspace mCurrentDataSpace;
-
-    /**
-     * mCurrentFrameNumber is the frame counter for the current texture.
-     * It gets set each time updateTexImage is called.
-     */
-    uint64_t mCurrentFrameNumber;
-
-    uint32_t mDefaultWidth, mDefaultHeight;
-
-    /**
-     * mFilteringEnabled indicates whether the transform matrix is computed for
-     * use with bilinear filtering. It defaults to true and is changed by
-     * setFilteringEnabled().
-     */
-    bool mFilteringEnabled;
-
-    /**
-     * mTexName is the name of the OpenGL texture to which streamed images will
-     * be bound when updateTexImage is called. It is set at construction time
-     * and can be changed with a call to attachToContext.
-     */
-    uint32_t mTexName;
-
-    /**
-     * mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
-     * extension should be used to prevent buffers from being dequeued before
-     * it's safe for them to be written. It gets set at construction time and
-     * never changes.
-     */
-    const bool mUseFenceSync;
-
-    /**
-     * mTexTarget is the GL texture target with which the GL texture object is
-     * associated.  It is set in the constructor and never changed.  It is
-     * almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android
-     * Browser.  In that case it is set to GL_TEXTURE_2D to allow
-     * glCopyTexSubImage to read from the texture.  This is a hack to work
-     * around a GL driver limitation on the number of FBO attachments, which the
-     * browser's tile cache exceeds.
-     */
-    const uint32_t mTexTarget;
-
-    /**
-     * mCurrentTexture is the buffer slot index of the buffer that is currently
-     * bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
-     * indicating that no buffer slot is currently bound to the texture. Note,
-     * however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-     * that no buffer is bound to the texture. A call to setBufferCount will
-     * reset mCurrentTexture to INVALID_BUFFER_SLOT.
-     */
-    int mCurrentTexture;
-
-    enum class OpMode { detached, attachedToView, attachedToGL };
-    /**
-     * mOpMode indicates whether the SurfaceTexture is currently attached to
-     * an OpenGL ES context or the HWUI view system.  For legacy reasons, this is initialized to,
-     * "attachedToGL" indicating that the SurfaceTexture is considered to be attached to
-     * whatever GL context is current at the time of the first updateTexImage call.
-     * It is set to "detached" by detachFromContext, and then set to "attachedToGL" again by
-     * attachToContext.
-     * attachToView/detachFromView are used to attach/detach from HWUI view system.
-     */
-    OpMode mOpMode;
-
-    /**
-     * mEGLConsumer has SurfaceTexture logic used when attached to GL context.
-     */
-    EGLConsumer mEGLConsumer;
-
-    /**
-     * mImageConsumer has SurfaceTexture logic used when attached to HWUI view system.
-     */
-    ImageConsumer mImageConsumer;
-
-    friend class ImageConsumer;
-    friend class EGLConsumer;
-};
-
-// ----------------------------------------------------------------------------
-}  // namespace android
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index e7124df..91a808d 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -29,6 +29,7 @@
 
 #include <gtest/gtest.h>
 #include <memory>
+#include <unordered_map>
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/services/Android.bp b/libs/services/Android.bp
index 1b9939d..b0fad57d 100644
--- a/libs/services/Android.bp
+++ b/libs/services/Android.bp
@@ -22,6 +22,7 @@
         "src/os/DropBoxManager.cpp",
         "src/os/StatsDimensionsValue.cpp",
         "src/os/StatsLogEventWrapper.cpp",
+        "src/util/StatsEvent.cpp",
     ],
 
     shared_libs: [
diff --git a/libs/services/include/android/util/StatsEvent.h b/libs/services/include/android/util/StatsEvent.h
new file mode 100644
index 0000000..4863117
--- /dev/null
+++ b/libs/services/include/android/util/StatsEvent.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef STATS_EVENT_H
+#define STATS_EVENT_H
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <vector>
+
+namespace android {
+namespace util {
+class StatsEvent : public android::Parcelable {
+    public:
+        StatsEvent();
+
+        StatsEvent(StatsEvent&& in) = default;
+
+        android::status_t writeToParcel(android::Parcel* out) const;
+
+        android::status_t readFromParcel(const android::Parcel* in);
+
+    private:
+        int mAtomTag;
+        std::vector<uint8_t> mBuffer;
+};
+} // Namespace util
+} // Namespace android
+
+#endif  // STATS_ EVENT_H
\ No newline at end of file
diff --git a/libs/services/src/util/StatsEvent.cpp b/libs/services/src/util/StatsEvent.cpp
new file mode 100644
index 0000000..8b85791
--- /dev/null
+++ b/libs/services/src/util/StatsEvent.cpp
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android/util/StatsEvent.h>
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/Status.h>
+#include <vector>
+
+using android::Parcel;
+using android::Parcelable;
+using android::status_t;
+using std::vector;
+
+namespace android {
+namespace util {
+
+StatsEvent::StatsEvent(){};
+
+status_t StatsEvent::writeToParcel(Parcel* out) const {
+    // Implement me if desired. We don't currently use this.
+    ALOGE("Cannot do c++ StatsEvent.writeToParcel(); it is not implemented.");
+    (void)out;  // To prevent compile error of unused parameter 'out'
+    return UNKNOWN_ERROR;
+};
+
+status_t StatsEvent::readFromParcel(const Parcel* in) {
+    status_t res = OK;
+    if (in == NULL) {
+        ALOGE("statsd received parcel argument was NULL.");
+        return BAD_VALUE;
+    }
+    if ((res = in->readInt32(&mAtomTag)) != OK) {
+        ALOGE("statsd could not read atom tag from parcel");
+        return res;
+    }
+    if ((res = in->readByteVector(&mBuffer)) != OK) {
+        ALOGE("statsd could not read buffer from parcel");
+        return res;
+    }
+    return NO_ERROR;
+};
+
+} // Namespace util
+} // Namespace android
diff --git a/location/TEST_MAPPING b/location/TEST_MAPPING
deleted file mode 100644
index 2f38627..0000000
--- a/location/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsLocationCoarseTestCases"
-    },
-    {
-      "name": "CtsLocationNoneTestCases"
-    }
-  ]
-}
diff --git a/location/java/android/location/GnssStatus.java b/location/java/android/location/GnssStatus.java
index 211a0cb..2f1eeda 100644
--- a/location/java/android/location/GnssStatus.java
+++ b/location/java/android/location/GnssStatus.java
@@ -16,18 +16,28 @@
 
 package android.location;
 
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 
 /**
- * This class represents the current state of the GNSS engine.
- * This class is used in conjunction with the {@link GnssStatus.Callback}.
+ * This class represents the current state of the GNSS engine and is used in conjunction with
+ * {@link GnssStatus.Callback}.
+ *
+ * @see LocationManager#registerGnssStatusCallback
+ * @see GnssStatus.Callback
  */
 public final class GnssStatus {
+
     // these must match the definitions in gps.h
+    //
+    // Note: these constants are also duplicated in GnssStatusCompat.java in the androidx support
+    // library. if adding a constellation, please update that file as well.
 
     /** Unknown constellation type. */
     public static final int CONSTELLATION_UNKNOWN = 0;
@@ -48,75 +58,88 @@
     /** @hide */
     public static final int CONSTELLATION_COUNT = 8;
 
-    /** @hide */
-    public static final int GNSS_SV_FLAGS_NONE = 0;
-    /** @hide */
-    public static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0);
-    /** @hide */
-    public static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
-    /** @hide */
-    public static final int GNSS_SV_FLAGS_USED_IN_FIX = (1 << 2);
-    /** @hide */
-    public static final int GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY = (1 << 3);
+    private static final int SVID_FLAGS_NONE = 0;
+    private static final int SVID_FLAGS_HAS_EPHEMERIS_DATA = (1 << 0);
+    private static final int SVID_FLAGS_HAS_ALMANAC_DATA = (1 << 1);
+    private static final int SVID_FLAGS_USED_IN_FIX = (1 << 2);
+    private static final int SVID_FLAGS_HAS_CARRIER_FREQUENCY = (1 << 3);
 
-    /** @hide */
-    public static final int SVID_SHIFT_WIDTH = 8;
-    /** @hide */
-    public static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
-    /** @hide */
-    public static final int CONSTELLATION_TYPE_MASK = 0xf;
+    private static final int SVID_SHIFT_WIDTH = 8;
+    private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
+    private static final int CONSTELLATION_TYPE_MASK = 0xf;
 
     /**
      * Used for receiving notifications when GNSS events happen.
+     *
+     * @see LocationManager#registerGnssStatusCallback
      */
     public static abstract class Callback {
         /**
          * Called when GNSS system has started.
          */
-        public void onStarted() {}
+        public void onStarted() {
+        }
 
         /**
          * Called when GNSS system has stopped.
          */
-        public void onStopped() {}
+        public void onStopped() {
+        }
 
         /**
          * Called when the GNSS system has received its first fix since starting.
+         *
          * @param ttffMillis the time from start to first fix in milliseconds.
          */
-        public void onFirstFix(int ttffMillis) {}
+        public void onFirstFix(int ttffMillis) {
+        }
 
         /**
          * Called periodically to report GNSS satellite status.
+         *
          * @param status the current status of all satellites.
          */
-        public void onSatelliteStatusChanged(GnssStatus status) {}
+        public void onSatelliteStatusChanged(@NonNull GnssStatus status) {
+        }
     }
 
     /**
      * Constellation type.
+     *
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({CONSTELLATION_UNKNOWN, CONSTELLATION_GPS, CONSTELLATION_SBAS, CONSTELLATION_GLONASS,
             CONSTELLATION_QZSS, CONSTELLATION_BEIDOU, CONSTELLATION_GALILEO, CONSTELLATION_IRNSS})
-    public @interface ConstellationType {}
-
-    final int[] mSvidWithFlags;
-    final float[] mCn0DbHz;
-    final float[] mElevations;
-    final float[] mAzimuths;
-    final int mSvCount;
-    final float[] mCarrierFrequencies;
+    public @interface ConstellationType {
+    }
 
     /**
+     * Create a GnssStatus that wraps the given arguments without any additional overhead. Callers
+     * are responsible for guaranteeing that the arguments are never modified after calling this
+     * method.
+     *
      * @hide
      */
-    public GnssStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
+    @NonNull
+    public static GnssStatus wrap(int svCount, int[] svidWithFlags, float[] cn0DbHzs,
+            float[] elevations, float[] azimuths, float[] carrierFrequencies) {
+        return new GnssStatus(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
+                carrierFrequencies);
+    }
+
+    private final int mSvCount;
+    private final int[] mSvidWithFlags;
+    private final float[] mCn0DbHzs;
+    private final float[] mElevations;
+    private final float[] mAzimuths;
+    private final float[] mCarrierFrequencies;
+
+    private GnssStatus(int svCount, int[] svidWithFlags, float[] cn0DbHzs, float[] elevations,
             float[] azimuths, float[] carrierFrequencies) {
         mSvCount = svCount;
         mSvidWithFlags = svidWithFlags;
-        mCn0DbHz = cn0s;
+        mCn0DbHzs = cn0DbHzs;
         mElevations = elevations;
         mAzimuths = azimuths;
         mCarrierFrequencies = carrierFrequencies;
@@ -125,6 +148,7 @@
     /**
      * Gets the total number of satellites in satellite list.
      */
+    @IntRange(from = 0)
     public int getSatelliteCount() {
         return mSvCount;
     }
@@ -132,11 +156,11 @@
     /**
      * Retrieves the constellation type of the satellite at the specified index.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
     @ConstellationType
-    public int getConstellationType(int satIndex) {
-        return ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+    public int getConstellationType(@IntRange(from = 0) int satelliteIndex) {
+        return ((mSvidWithFlags[satelliteIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
                 & CONSTELLATION_TYPE_MASK);
     }
 
@@ -154,110 +178,113 @@
      * <li>SBAS: 120-151, 183-192</li>
      * <li>GLONASS: One of: OSN, or FCN+100
      * <ul>
-     *   <li>1-24 as the orbital slot number (OSN) (preferred, if known)</li>
-     *   <li>93-106 as the frequency channel number (FCN) (-7 to +6) plus 100.
-     *   i.e. encode FCN of -7 as 93, 0 as 100, and +6 as 106</li>
+     * <li>1-24 as the orbital slot number (OSN) (preferred, if known)</li>
+     * <li>93-106 as the frequency channel number (FCN) (-7 to +6) plus 100.
+     * i.e. encode FCN of -7 as 93, 0 as 100, and +6 as 106</li>
      * </ul></li>
      * <li>QZSS: 193-200</li>
      * <li>Galileo: 1-36</li>
      * <li>Beidou: 1-37</li>
      * </ul>
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public int getSvid(int satIndex) {
-        return mSvidWithFlags[satIndex] >> SVID_SHIFT_WIDTH;
+    @IntRange(from = 1, to = 200)
+    public int getSvid(@IntRange(from = 0) int satelliteIndex) {
+        return mSvidWithFlags[satelliteIndex] >> SVID_SHIFT_WIDTH;
     }
 
     /**
      * Retrieves the carrier-to-noise density at the antenna of the satellite at the specified index
      * in dB-Hz.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public float getCn0DbHz(int satIndex) {
-        return mCn0DbHz[satIndex];
+    @FloatRange(from = 0, to = 63)
+    public float getCn0DbHz(@IntRange(from = 0) int satelliteIndex) {
+        return mCn0DbHzs[satelliteIndex];
     }
 
     /**
      * Retrieves the elevation of the satellite at the specified index.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public float getElevationDegrees(int satIndex) {
-        return mElevations[satIndex];
+    @FloatRange(from = -90, to = 90)
+    public float getElevationDegrees(@IntRange(from = 0) int satelliteIndex) {
+        return mElevations[satelliteIndex];
     }
 
     /**
      * Retrieves the azimuth the satellite at the specified index.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public float getAzimuthDegrees(int satIndex) {
-        return mAzimuths[satIndex];
+    @FloatRange(from = 0, to = 360)
+    public float getAzimuthDegrees(@IntRange(from = 0) int satelliteIndex) {
+        return mAzimuths[satelliteIndex];
     }
 
     /**
      * Reports whether the satellite at the specified index has ephemeris data.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public boolean hasEphemerisData(int satIndex) {
-        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
+    public boolean hasEphemerisData(@IntRange(from = 0) int satelliteIndex) {
+        return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_EPHEMERIS_DATA) != 0;
     }
 
     /**
      * Reports whether the satellite at the specified index has almanac data.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public boolean hasAlmanacData(int satIndex) {
-        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
+    public boolean hasAlmanacData(@IntRange(from = 0) int satelliteIndex) {
+        return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_ALMANAC_DATA) != 0;
     }
 
     /**
      * Reports whether the satellite at the specified index was used in the calculation of the most
      * recent position fix.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public boolean usedInFix(int satIndex) {
-        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+    public boolean usedInFix(@IntRange(from = 0) int satelliteIndex) {
+        return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_USED_IN_FIX) != 0;
     }
 
     /**
-     * Reports whether a valid {@link #getCarrierFrequencyHz(int satIndex)} is available.
+     * Reports whether a valid {@link #getCarrierFrequencyHz(int satelliteIndex)} is available.
      *
-     * @param satIndex the index of the satellite in the list.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public boolean hasCarrierFrequencyHz(int satIndex) {
-        return (mSvidWithFlags[satIndex] & GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) != 0;
+    public boolean hasCarrierFrequencyHz(@IntRange(from = 0) int satelliteIndex) {
+        return (mSvidWithFlags[satelliteIndex] & SVID_FLAGS_HAS_CARRIER_FREQUENCY) != 0;
     }
 
     /**
      * Gets the carrier frequency of the signal tracked.
      *
-     * <p>For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60 MHz,
-     * L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary
+     * <p>For example it can be the GPS central frequency for L1 = 1575.45 MHz, or L2 = 1227.60
+     * MHz, L5 = 1176.45 MHz, varying GLO channels, etc. If the field is not set, it is the primary
      * common use central frequency, e.g. L1 = 1575.45 MHz for GPS.
      *
      * For an L1, L5 receiver tracking a satellite on L1 and L5 at the same time, two measurements
-     * will be reported for this same satellite, in one all the values related to L1 will be filled,
-     * and in the other all of the values related to L5 will be filled.
+     * will be reported for this same satellite, in one all the values related to L1 will be
+     * filled, and in the other all of the values related to L5 will be filled.
      *
-     * <p>The value is only available if {@link #hasCarrierFrequencyHz(int satIndex)} is {@code true}.
+     * <p>The value is only available if {@link #hasCarrierFrequencyHz(int satelliteIndex)} is
+     * {@code true}.
      *
-     * @param satIndex the index of the satellite in the list.
-     *
-     * @return the carrier frequency of the signal tracked in Hz.
+     * @param satelliteIndex An index from zero to {@link #getSatelliteCount()} - 1
      */
-    public float getCarrierFrequencyHz(int satIndex) {
-        return mCarrierFrequencies[satIndex];
+    @FloatRange(from = 0)
+    public float getCarrierFrequencyHz(@IntRange(from = 0) int satelliteIndex) {
+        return mCarrierFrequencies[satelliteIndex];
     }
 
     /**
-     * Returns the string representation of a constellation type. For example,
-     * {@link #CONSTELLATION_GPS} is represented by the string GPS.
+     * Returns the string representation of a constellation type.
      *
      * @param constellationType the constellation type.
      * @return the string representation.
@@ -286,4 +313,108 @@
                 return Integer.toString(constellationType);
         }
     }
+
+    /**
+     * Builder class to help create new GnssStatus instances.
+     */
+    public static final class Builder {
+
+        private final ArrayList<GnssSvInfo> mSatellites = new ArrayList<>();
+
+        /**
+         * Adds a new satellite to the Builder.
+         *
+         * @param constellationType one of the CONSTELLATION_* constants
+         * @param svid the space vehicle identifier
+         * @param cn0DbHz carrier-to-noise density at the antenna in dB-Hz
+         * @param elevation satellite elevation in degrees
+         * @param azimuth satellite azimuth in degrees
+         * @param hasEphemeris whether the satellite has ephemeris data
+         * @param hasAlmanac whether the satellite has almanac data
+         * @param usedInFix whether the satellite was used in the most recent location fix
+         * @param hasCarrierFrequency whether carrier frequency data is available
+         * @param carrierFrequency satellite carrier frequency in Hz
+         */
+        @NonNull
+        public Builder addSatellite(@ConstellationType int constellationType,
+                @IntRange(from = 1, to = 200) int svid,
+                @FloatRange(from = 0, to = 63) float cn0DbHz,
+                @FloatRange(from = -90, to = 90) float elevation,
+                @FloatRange(from = 0, to = 360) float azimuth,
+                boolean hasEphemeris,
+                boolean hasAlmanac,
+                boolean usedInFix,
+                boolean hasCarrierFrequency,
+                @FloatRange(from = 0) float carrierFrequency) {
+            mSatellites.add(new GnssSvInfo(constellationType, svid, cn0DbHz, elevation, azimuth,
+                    hasEphemeris, hasAlmanac, usedInFix, hasCarrierFrequency, carrierFrequency));
+            return this;
+        }
+
+        /**
+         * Clears all satellites in the Builder.
+         */
+        @NonNull
+        public Builder clearSatellites() {
+            mSatellites.clear();
+            return this;
+        }
+
+        /**
+         * Builds a new GnssStatus based on the satellite information in the Builder.
+         */
+        @NonNull
+        public GnssStatus build() {
+            int svCount = mSatellites.size();
+            int[] svidWithFlags = new int[svCount];
+            float[] cn0DbHzs = new float[svCount];
+            float[] elevations = new float[svCount];
+            float[] azimuths = new float[svCount];
+            float[] carrierFrequencies = new float[svCount];
+
+            for (int i = 0; i < svidWithFlags.length; i++) {
+                svidWithFlags[i] = mSatellites.get(i).mSvidWithFlags;
+            }
+            for (int i = 0; i < cn0DbHzs.length; i++) {
+                cn0DbHzs[i] = mSatellites.get(i).mCn0DbHz;
+            }
+            for (int i = 0; i < elevations.length; i++) {
+                elevations[i] = mSatellites.get(i).mElevation;
+            }
+            for (int i = 0; i < azimuths.length; i++) {
+                azimuths[i] = mSatellites.get(i).mAzimuth;
+            }
+            for (int i = 0; i < carrierFrequencies.length; i++) {
+                carrierFrequencies[i] = mSatellites.get(i).mCarrierFrequency;
+            }
+
+            return wrap(svCount, svidWithFlags, cn0DbHzs, elevations, azimuths,
+                    carrierFrequencies);
+        }
+    }
+
+    private static class GnssSvInfo {
+
+        private final int mSvidWithFlags;
+        private final float mCn0DbHz;
+        private final float mElevation;
+        private final float mAzimuth;
+        private final float mCarrierFrequency;
+
+        private GnssSvInfo(int constellationType, int svid, float cn0DbHz,
+                float elevation, float azimuth, boolean hasEphemeris, boolean hasAlmanac,
+                boolean usedInFix, boolean hasCarrierFrequency, float carrierFrequency) {
+            mSvidWithFlags = (svid << SVID_SHIFT_WIDTH)
+                    | ((constellationType & CONSTELLATION_TYPE_MASK)
+                    << CONSTELLATION_TYPE_SHIFT_WIDTH)
+                    | (hasEphemeris ? SVID_FLAGS_HAS_EPHEMERIS_DATA : SVID_FLAGS_NONE)
+                    | (hasAlmanac ? SVID_FLAGS_HAS_ALMANAC_DATA : SVID_FLAGS_NONE)
+                    | (usedInFix ? SVID_FLAGS_USED_IN_FIX : SVID_FLAGS_NONE)
+                    | (hasCarrierFrequency ? SVID_FLAGS_HAS_CARRIER_FREQUENCY : SVID_FLAGS_NONE);
+            mCn0DbHz = cn0DbHz;
+            mElevation = elevation;
+            mAzimuth = azimuth;
+            mCarrierFrequency = carrierFrequency;
+        }
+    }
 }
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 609a15e..496885c 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -16,8 +16,7 @@
 
 package android.location;
 
-import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
+import android.annotation.NonNull;
 import android.util.SparseArray;
 
 import java.util.Iterator;
@@ -25,20 +24,18 @@
 
 
 /**
- * This class represents the current state of the GPS engine.
+ * This class represents the current state of the GPS engine and is used in conjunction with {@link
+ * GpsStatus.Listener}.
  *
- * <p>This class is used in conjunction with the {@link Listener} interface.
- *
- * @deprecated use {@link GnssStatus} and {@link GnssStatus.Callback}.
+ * @deprecated Use {@link GnssStatus} instead.
  */
 @Deprecated
 public final class GpsStatus {
-    private static final int NUM_SATELLITES = 255;
+    private static final int MAX_SATELLITES = 255;
     private static final int GLONASS_SVID_OFFSET = 64;
     private static final int BEIDOU_SVID_OFFSET = 200;
     private static final int SBAS_SVID_OFFSET = -87;
 
-    /* These package private values are modified by the LocationManager class */
     private int mTimeToFirstFix;
     private final SparseArray<GpsSatellite> mSatellites = new SparseArray<>();
 
@@ -80,12 +77,7 @@
         }
     }
 
-    private Iterable<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
-        @Override
-        public Iterator<GpsSatellite> iterator() {
-            return new SatelliteIterator();
-        }
-    };
+    private Iterable<GpsSatellite> mSatelliteList = SatelliteIterator::new;
 
     /**
      * Event sent when the GPS system has started.
@@ -111,7 +103,8 @@
 
     /**
      * Used for receiving notifications when GPS status has changed.
-     * @deprecated use {@link GnssStatus.Callback} instead.
+     *
+     * @deprecated Use {@link GnssStatus.Callback} instead.
      */
     @Deprecated
     public interface Listener {
@@ -148,17 +141,31 @@
         void onNmeaReceived(long timestamp, String nmea);
     }
 
-    // For API-compat a public ctor() is not available
-    GpsStatus() {}
+    /**
+     * Builds a GpsStatus from the given GnssStatus.
+     */
+    @NonNull
+    public static GpsStatus create(@NonNull GnssStatus gnssStatus, int timeToFirstFix) {
+        GpsStatus status = new GpsStatus();
+        status.setStatus(gnssStatus, timeToFirstFix);
+        return status;
+    }
 
-    private void setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
-            float[] azimuths) {
-        clearSatellites();
-        for (int i = 0; i < svCount; i++) {
-            final int constellationType =
-                    (svidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
-                    & GnssStatus.CONSTELLATION_TYPE_MASK;
-            int prn = svidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH;
+    private GpsStatus() {
+    }
+
+    /**
+     * @hide
+     */
+    void setStatus(GnssStatus status, int timeToFirstFix) {
+        for (int i = 0; i < mSatellites.size(); i++) {
+            mSatellites.valueAt(i).mValid = false;
+        }
+
+        mTimeToFirstFix = timeToFirstFix;
+        for (int i = 0; i < status.getSatelliteCount(); i++) {
+            int constellationType = status.getConstellationType(i);
+            int prn = status.getSvid(i);
             // Other satellites passed through these APIs before GnssSvStatus was availble.
             // GPS, SBAS & QZSS can pass through at their nominally
             // assigned prn number (as long as it fits in the valid 0-255 range below.)
@@ -175,45 +182,27 @@
                     (constellationType != GnssStatus.CONSTELLATION_QZSS)) {
                 continue;
             }
-            if (prn > 0 && prn <= NUM_SATELLITES) {
-                GpsSatellite satellite = mSatellites.get(prn);
-                if (satellite == null) {
-                    satellite = new GpsSatellite(prn);
-                    mSatellites.put(prn, satellite);
-                }
-
-                satellite.mValid = true;
-                satellite.mSnr = cn0s[i];
-                satellite.mElevation = elevations[i];
-                satellite.mAzimuth = azimuths[i];
-                satellite.mHasEphemeris =
-                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) != 0;
-                satellite.mHasAlmanac =
-                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) != 0;
-                satellite.mUsedInFix =
-                        (svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0;
+            if (prn <= 0 || prn > MAX_SATELLITES) {
+                continue;
             }
+
+            GpsSatellite satellite = mSatellites.get(prn);
+            if (satellite == null) {
+                satellite = new GpsSatellite(prn);
+                mSatellites.put(prn, satellite);
+            }
+
+            satellite.mValid = true;
+            satellite.mSnr = status.getCn0DbHz(i);
+            satellite.mElevation = status.getElevationDegrees(i);
+            satellite.mAzimuth = status.getAzimuthDegrees(i);
+            satellite.mHasEphemeris = status.hasEphemerisData(i);
+            satellite.mHasAlmanac = status.hasAlmanacData(i);
+            satellite.mUsedInFix = status.usedInFix(i);
         }
     }
 
     /**
-     * Copies GPS satellites information from GnssStatus object.
-     * Since this method is only used within {@link LocationManager#getGpsStatus},
-     * it does not need to be synchronized.
-     * @hide
-     */
-    void setStatus(GnssStatus status, int timeToFirstFix) {
-        mTimeToFirstFix = timeToFirstFix;
-        setStatus(status.mSvCount, status.mSvidWithFlags, status.mCn0DbHz, status.mElevations,
-                status.mAzimuths);
-    }
-
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    void setTimeToFirstFix(int ttff) {
-        mTimeToFirstFix = ttff;
-    }
-
-    /**
      * Returns the time required to receive the first fix since the most recent
      * restart of the GPS engine.
      *
@@ -240,14 +229,7 @@
      * @return the maximum number of satellites
      */
     public int getMaxSatellites() {
-        return NUM_SATELLITES;
+        return mSatellites.size();
     }
 
-    private void clearSatellites() {
-        int satellitesCount = mSatellites.size();
-        for (int i = 0; i < satellitesCount; i++) {
-            GpsSatellite satellite = mSatellites.valueAt(i);
-            satellite.mValid = false;
-        }
-    }
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index c48f6e8..75e1cd4 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
@@ -1810,15 +1810,22 @@
     @Deprecated
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
-        if (status == null) {
-            status = new GpsStatus();
+        UnsupportedOperationException ex = new UnsupportedOperationException(
+                "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
+            throw ex;
+        } else {
+            Log.w(TAG, ex);
         }
-        // When mGnssStatus is null, that means that this method is called outside
-        // onGpsStatusChanged().  Return an empty status to maintain backwards compatibility.
+
         GnssStatus gnssStatus = mGnssStatusListenerManager.getGnssStatus();
         int ttff = mGnssStatusListenerManager.getTtff();
         if (gnssStatus != null) {
-            status.setStatus(gnssStatus, ttff);
+            if (status == null) {
+                status = GpsStatus.create(gnssStatus, ttff);
+            } else {
+                status.setStatus(gnssStatus, ttff);
+            }
         }
         return status;
     }
@@ -1837,8 +1844,8 @@
     @RequiresPermission(ACCESS_FINE_LOCATION)
     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
         UnsupportedOperationException ex = new UnsupportedOperationException(
-                "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
-        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+                "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
             throw ex;
         } else {
             Log.w(TAG, ex);
@@ -1862,8 +1869,8 @@
     @Deprecated
     public void removeGpsStatusListener(GpsStatus.Listener listener) {
         UnsupportedOperationException ex = new UnsupportedOperationException(
-                "GpsStatus APIs not supported in R and above, use GnssStatus APIs instead");
-        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.R) {
+                "GpsStatus APIs not supported in S and above, use GnssStatus APIs instead");
+        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.R) {
             throw ex;
         } else {
             Log.w(TAG, ex);
@@ -1955,23 +1962,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.
@@ -2636,10 +2641,47 @@
 
         @Override
         public void onRemoved() {
-            unregister();
-            synchronized (mListeners) {
-                mListeners.remove(mListener, this);
+            // TODO: onRemoved is necessary to GC hanging listeners, but introduces some interesting
+            //  broken edge cases. luckily these edge cases are quite unlikely. consider the
+            //  following interleaving for instance:
+            //    1) client adds single shot location request (A)
+            //    2) client gets removal callback, and schedules it for execution
+            //    3) client replaces single shot request with a different location request (B)
+            //    4) prior removal callback is executed, removing location request (B) incorrectly
+            //  what's needed is a way to identify which listener a callback belongs to. currently
+            //  we reuse the same transport object for the same listeners (so that we don't leak
+            //  transport objects on the server side). there seem to be two solutions:
+            //    1) when reregistering a request, first unregister the current transport, then
+            //       register with a new transport object (never reuse transport objects) - the
+            //       downside is that this breaks the server's knowledge that the request is the
+            //       same object, and thus breaks optimizations such as reusing the same transport
+            //       state.
+            //    2) pass some other type of marker in addition to the transport (for example an
+            //       incrementing integer representing the transport "version"), and pass this
+            //       marker back into callbacks so that each callback knows which transport
+            //       "version" it belongs to and can not execute itself if the version does not
+            //       match.
+            //  (1) seems like the preferred solution as it's simpler to implement and the above
+            //  mentioned server optimizations are not terribly important (they can be bypassed by
+            //  clients that use a new listener every time anyways).
+
+            Executor currentExecutor = mExecutor;
+            if (currentExecutor == null) {
+                // we've already been unregistered, no work to do anyways
+                return;
             }
+
+            // must be executed on the same executor so callback execution cannot be reordered
+            currentExecutor.execute(() -> {
+                if (currentExecutor != mExecutor) {
+                    return;
+                }
+
+                unregister();
+                synchronized (mListeners) {
+                    mListeners.remove(mListener, this);
+                }
+            });
         }
 
         private void locationCallbackFinished() {
@@ -2777,8 +2819,8 @@
             @Override
             public void onSvStatusChanged(int svCount, int[] svidWithFlags, float[] cn0s,
                     float[] elevations, float[] azimuths, float[] carrierFreqs) {
-                GnssStatus localStatus = new GnssStatus(svCount, svidWithFlags, cn0s, elevations,
-                        azimuths, carrierFreqs);
+                GnssStatus localStatus = GnssStatus.wrap(svCount, svidWithFlags, cn0s,
+                        elevations, azimuths, carrierFreqs);
                 mGnssStatus = localStatus;
                 execute((callback) -> callback.onSatelliteStatusChanged(localStatus));
             }
diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
index 07bfe02..e0bff74 100644
--- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
+++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java
@@ -188,22 +188,18 @@
 
     /**
     * Logs sv status data
-    *
-    * @param svCount
-    * @param svidWithFlags
-    * @param svCarrierFreqs
     */
-    public void logSvStatus(int svCount, int[] svidWithFlags, float[] svCarrierFreqs) {
+    public void logSvStatus(GnssStatus status) {
         boolean isL5 = false;
         // Calculate SvStatus Information
-        for (int i = 0; i < svCount; i++) {
-            if ((svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) != 0) {
+        for (int i = 0; i < status.getSatelliteCount(); i++) {
+            if (status.hasCarrierFrequencyHz(i)) {
                 mNumSvStatus++;
-                isL5 = isL5Sv(svCarrierFreqs[i]);
+                isL5 = isL5Sv(status.getCarrierFrequencyHz(i));
                 if (isL5) {
                     mNumL5SvStatus++;
                 }
-                if ((svidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+                if (status.usedInFix(i)) {
                     mNumSvStatusUsedInFix++;
                     if (isL5) {
                         mNumL5SvStatusUsedInFix++;
@@ -211,15 +207,10 @@
                 }
             }
         }
-        return;
     }
 
     /**
     * Logs CN0 when at least 4 SVs are available L5 Only
-    *
-    * @param svCount
-    * @param cn0s
-    * @param svCarrierFreqs
     */
     private void logCn0L5(int svCount, float[] cn0s, float[] svCarrierFreqs) {
         if (svCount == 0 || cn0s == null || cn0s.length == 0 || cn0s.length < svCount
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ac5a9f8..3a092a0 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -710,7 +710,7 @@
          * @return the same Builder instance.
          */
         public Builder setFlags(int flags) {
-            flags &= AudioAttributes.FLAG_ALL;
+            flags &= AudioAttributes.FLAG_ALL_PUBLIC;
             mFlags |= flags;
             return this;
         }
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9ad7f2a..d552491 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1,4 +1,5 @@
 /*
+/*
  * Copyright (C) 2007 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -1931,12 +1932,11 @@
      * application when it places a phone call, as it will cause signals from the radio layer
      * to feed the platform mixer.
      *
-     * @param mode  the requested audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE},
-     *              {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}).
+     * @param mode  the requested audio mode.
      *              Informs the HAL about the current audio state so that
      *              it can route the audio appropriately.
      */
-    public void setMode(int mode) {
+    public void setMode(@AudioMode int mode) {
         final IAudioService service = getService();
         try {
             service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
@@ -1948,14 +1948,47 @@
     /**
      * Returns the current audio mode.
      *
-     * @return      the current audio mode ({@link #MODE_NORMAL}, {@link #MODE_RINGTONE},
-     *              {@link #MODE_IN_CALL} or {@link #MODE_IN_COMMUNICATION}).
-     *              Returns the current current audio state from the HAL.
+     * @return      the current audio mode.
      */
+    @AudioMode
     public int getMode() {
         final IAudioService service = getService();
         try {
-            return service.getMode();
+            int mode = service.getMode();
+            int sdk;
+            try {
+                sdk = getContext().getApplicationInfo().targetSdkVersion;
+            } catch (NullPointerException e) {
+                // some tests don't have a Context
+                sdk = Build.VERSION.SDK_INT;
+            }
+            if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
+                mode = MODE_IN_CALL;
+            }
+            return mode;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+    * Indicates if the platform supports a special call screening and call monitoring mode.
+    * <p>
+    * When this mode is supported, it is possible to perform call screening and monitoring
+    * functions while other use cases like music or movie playback are active.
+    * <p>
+    * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
+    * call screening mode.
+    * <p>
+    * If call screening mode is not supported, setting mode to
+    * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
+    *  {@link #getMode()}.
+    * @return true if call screening mode is supported, false otherwise.
+    */
+    public boolean isCallScreeningModeSupported() {
+        final IAudioService service = getService();
+        try {
+            return service.isCallScreeningModeSupported();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1989,6 +2022,22 @@
      * In communication audio mode. An audio/video chat or VoIP call is established.
      */
     public static final int MODE_IN_COMMUNICATION   = AudioSystem.MODE_IN_COMMUNICATION;
+    /**
+     * Call screening in progress. Call is connected and audio is accessible to call
+     * screening applications but other audio use cases are still possible.
+     */
+    public static final int MODE_CALL_SCREENING     = AudioSystem.MODE_CALL_SCREENING;
+
+    /** @hide */
+    @IntDef(flag = false, prefix = "MODE_", value = {
+            MODE_NORMAL,
+            MODE_RINGTONE,
+            MODE_IN_CALL,
+            MODE_IN_COMMUNICATION,
+            MODE_CALL_SCREENING }
+    )
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioMode {}
 
     /* Routing bits for setRouting/getRouting API */
     /**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index bb731a8..a3a8777 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -132,7 +132,8 @@
     public static final int MODE_RINGTONE           = 1;
     public static final int MODE_IN_CALL            = 2;
     public static final int MODE_IN_COMMUNICATION   = 3;
-    public static final int NUM_MODES               = 4;
+    public static final int MODE_CALL_SCREENING     = 4;
+    public static final int NUM_MODES               = 5;
 
     public static String modeToString(int mode) {
         switch (mode) {
@@ -142,6 +143,7 @@
             case MODE_INVALID: return "MODE_INVALID";
             case MODE_NORMAL: return "MODE_NORMAL";
             case MODE_RINGTONE: return "MODE_RINGTONE";
+            case MODE_CALL_SCREENING: return "MODE_CALL_SCREENING";
             default: return "unknown mode (" + mode + ")";
         }
     }
@@ -1124,6 +1126,17 @@
      */
     public static native boolean isHapticPlaybackSupported();
 
+    /**
+     * Send audio HAL server process pids to native audioserver process for use
+     * when generating audio HAL servers tombstones
+     */
+    public static native int setAudioHalPids(int[] pids);
+
+    /**
+     * @see AudioManager#isCallScreeningModeSupported()
+     */
+    public static native boolean isCallScreeningModeSupported();
+
     // Items shared with audio service
 
     /**
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index d6a4ea7..5ac6f7f 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -237,11 +237,56 @@
     public static final String TAG_NEW_SUBFILE_TYPE = "NewSubfileType";
     /** Type is String. */
     public static final String TAG_OECF = "OECF";
-    /** Type is String. {@hide} */
+    /**
+     *  <p>A tag used to record the offset from UTC (the time difference from Universal Time
+     *  Coordinated including daylight saving time) of the time of DateTime tag. The format when
+     *  recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+     *  the offsets are unknown, all the character spaces except colons (":") should be filled
+     *  with blank characters, or else the Interoperability field should be filled with blank
+     *  characters. The character string length is 7 Bytes including NULL for termination. When
+     *  the field is left blank, it is treated as unknown.</p>
+     *
+     *  <ul>
+     *      <li>Tag = 36880</li>
+     *      <li>Type = String</li>
+     *      <li>Length = 7</li>
+     *      <li>Default = None</li>
+     *  </ul>
+     */
     public static final String TAG_OFFSET_TIME = "OffsetTime";
-    /** Type is String. {@hide} */
+    /**
+     *  <p>A tag used to record the offset from UTC (the time difference from Universal Time
+     *  Coordinated including daylight saving time) of the time of DateTimeOriginal tag. The format
+     *  when recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+     *  the offsets are unknown, all the character spaces except colons (":") should be filled
+     *  with blank characters, or else the Interoperability field should be filled with blank
+     *  characters. The character string length is 7 Bytes including NULL for termination. When
+     *  the field is left blank, it is treated as unknown.</p>
+     *
+     *  <ul>
+     *      <li>Tag = 36881</li>
+     *      <li>Type = String</li>
+     *      <li>Length = 7</li>
+     *      <li>Default = None</li>
+     *  </ul>
+     */
     public static final String TAG_OFFSET_TIME_ORIGINAL = "OffsetTimeOriginal";
-    /** Type is String. {@hide} */
+    /**
+     *  <p>A tag used to record the offset from UTC (the time difference from Universal Time
+     *  Coordinated including daylight saving time) of the time of DateTimeDigitized tag. The format
+     *  when recording the offset is "±HH:MM". The part of "±" shall be recorded as "+" or "-". When
+     *  the offsets are unknown, all the character spaces except colons (":") should be filled
+     *  with blank characters, or else the Interoperability field should be filled with blank
+     *  characters. The character string length is 7 Bytes including NULL for termination. When
+     *  the field is left blank, it is treated as unknown.</p>
+     *
+     *  <ul>
+     *      <li>Tag = 36882</li>
+     *      <li>Type = String</li>
+     *      <li>Length = 7</li>
+     *      <li>Default = None</li>
+     *  </ul>
+     */
     public static final String TAG_OFFSET_TIME_DIGITIZED = "OffsetTimeDigitized";
     /** Type is int. */
     public static final String TAG_PIXEL_X_DIMENSION = "PixelXDimension";
@@ -461,6 +506,26 @@
     public static final int WHITEBALANCE_AUTO = 0;
     public static final int WHITEBALANCE_MANUAL = 1;
 
+    /**
+     * Constant used to indicate that the input stream contains the full image data.
+     * <p>
+     * The format of the image data should follow one of the image formats supported by this class.
+     */
+    public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0;
+    /**
+     * Constant used to indicate that the input stream contains only Exif data.
+     * <p>
+     * The format of the Exif-only data must follow the below structure:
+     *     Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
+     * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
+     */
+    public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1;
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STREAM_TYPE_FULL_IMAGE_DATA, STREAM_TYPE_EXIF_DATA_ONLY})
+    public @interface ExifStreamType {}
+
     // Maximum size for checking file type signature (see image_type_recognition_lite.cc)
     private static final int SIGNATURE_CHECK_SIZE = 5000;
 
@@ -1371,7 +1436,7 @@
     private AssetManager.AssetInputStream mAssetInputStream;
     private boolean mIsInputStream;
     private int mMimeType;
-    private boolean mIsStandalone;
+    private boolean mIsExifDataOnly;
     @UnsupportedAppUsage
     private final HashMap[] mAttributes = new HashMap[EXIF_TAGS.length];
     private Set<Integer> mHandledIfdOffsets = new HashSet<>(EXIF_TAGS.length);
@@ -1399,6 +1464,11 @@
 
     /**
      * Reads Exif tags from the specified image file.
+     *
+     * @param file the file of the image data
+     * @throws NullPointerException if file is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
     public ExifInterface(@NonNull File file) throws IOException {
         if (file == null) {
@@ -1409,6 +1479,11 @@
 
     /**
      * Reads Exif tags from the specified image file.
+     *
+     * @param filename the name of the file of the image data
+     * @throws NullPointerException if file name is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
     public ExifInterface(@NonNull String filename) throws IOException {
         if (filename == null) {
@@ -1421,6 +1496,11 @@
      * Reads Exif tags from the specified image file descriptor. Attribute mutation is supported
      * for writable and seekable file descriptors only. This constructor will not rewind the offset
      * of the given file descriptor. Developers should close the file descriptor after use.
+     *
+     * @param fileDescriptor the file descriptor of the image data
+     * @throws NullPointerException if file descriptor is null
+     * @throws IOException if an error occurs while duplicating the file descriptor via
+     *         {@link Os#dup(FileDescriptor)}.
      */
     public ExifInterface(@NonNull FileDescriptor fileDescriptor) throws IOException {
         if (fileDescriptor == null) {
@@ -1459,45 +1539,46 @@
     /**
      * Reads Exif tags from the specified image input stream. Attribute mutation is not supported
      * for input streams. The given input stream will proceed from its current position. Developers
-     * should close the input stream after use.
+     * should close the input stream after use. This constructor is not intended to be used with an
+     * input stream that performs any networking operations.
+     *
+     * @param inputStream the input stream that contains the image data
+     * @throws NullPointerException if the input stream is null
      */
     public ExifInterface(@NonNull InputStream inputStream) throws IOException {
         this(inputStream, false);
     }
 
     /**
-     * Reads Exif tags from the specified standalone input stream. Standalone data refers to Exif
-     * data that exists by itself and is not contained in a file format such as jpeg or png.
-     * The format of the standalone data must follow the below structure:
-     *     Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
-     * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
-     * <p>
-     * Attribute mutation is not supported for this constructor. The given input stream will proceed
-     * from its current position. Developers should close the input stream after use. This
-     * constructor is not intended to be used with an input stream that performs any networking
-     * operations.
+     * Reads Exif tags from the specified image input stream based on the stream type. Attribute
+     * mutation is not supported for input streams. The given input stream will proceed from its
+     * current position. Developers should close the input stream after use. This constructor is not
+     * intended to be used with an input stream that performs any networking operations.
      *
-     * @throws IOException if the data does not follow the aforementioned structure.
+     * @param inputStream the input stream that contains the image data
+     * @param streamType the type of input stream
+     * @throws NullPointerException if the input stream is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
-    @NonNull
-    public static ExifInterface fromStandalone(@NonNull InputStream inputStream)
+    public ExifInterface(@NonNull InputStream inputStream, @ExifStreamType int streamType)
             throws IOException {
-        if (isStandalone(inputStream)) {
-            return new ExifInterface(inputStream, true);
-        }
-        throw new IOException("Given data does not follow the structure of a standalone exif "
-                + "data.");
+        this(inputStream, (streamType == STREAM_TYPE_EXIF_DATA_ONLY) ? true : false);
     }
 
-    private ExifInterface(@NonNull InputStream inputStream, boolean isFromStandalone)
+    private ExifInterface(@NonNull InputStream inputStream, boolean shouldBeExifDataOnly)
             throws IOException {
         if (inputStream == null) {
             throw new NullPointerException("inputStream cannot be null");
         }
         mFilename = null;
 
-        if (isFromStandalone) {
-            mIsStandalone = true;
+        if (shouldBeExifDataOnly) {
+            if (!isExifDataOnly(inputStream)) {
+                Log.w(TAG, "Given data does not follow the structure of an Exif-only data.");
+                return;
+            }
+            mIsExifDataOnly = true;
             mAssetInputStream = null;
             mSeekableFileDescriptor = null;
         } else {
@@ -1835,10 +1916,9 @@
 
     /**
      * This function decides which parser to read the image data according to the given input stream
-     * type and the content of the input stream. In each case, it reads the first three bytes to
-     * determine whether the image data format is JPEG or not.
+     * type and the content of the input stream.
      */
-    private void loadAttributes(@NonNull InputStream in) throws IOException {
+    private void loadAttributes(@NonNull InputStream in) {
         if (in == null) {
             throw new NullPointerException("inputstream shouldn't be null");
         }
@@ -1849,7 +1929,7 @@
             }
 
             // Check file type
-            if (!mIsStandalone) {
+            if (!mIsExifDataOnly) {
                 in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
                 mMimeType = getMimeType((BufferedInputStream) in);
             }
@@ -1857,7 +1937,7 @@
             // Create byte-ordered input stream
             ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
 
-            if (!mIsStandalone) {
+            if (!mIsExifDataOnly) {
                 switch (mMimeType) {
                     case IMAGE_TYPE_JPEG: {
                         getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset
@@ -1924,11 +2004,14 @@
         }
     }
 
-    private static boolean isSeekableFD(FileDescriptor fd) throws IOException {
+    private static boolean isSeekableFD(FileDescriptor fd) {
         try {
             Os.lseek(fd, 0, OsConstants.SEEK_CUR);
             return true;
         } catch (ErrnoException e) {
+            if (DEBUG) {
+                Log.d(TAG, "The file descriptor for the given input is not seekable");
+            }
             return false;
         }
     }
@@ -2194,7 +2277,7 @@
         }
 
         if (mHasThumbnail) {
-            if (mIsStandalone) {
+            if (mIsExifDataOnly) {
                 return new long[] { mThumbnailOffset + mExifOffset, mThumbnailLength };
             }
             return new long[] { mThumbnailOffset, mThumbnailLength };
@@ -2658,16 +2741,20 @@
         return true;
     }
 
-    private static boolean isStandalone(InputStream inputStream) throws IOException {
-        byte[] signatureCheckBytes = new byte[IDENTIFIER_EXIF_APP1.length];
-        inputStream.read(signatureCheckBytes);
-
-        for (int i = 0; i < IDENTIFIER_EXIF_APP1.length; i++) {
-            if (signatureCheckBytes[i] != IDENTIFIER_EXIF_APP1[i]) {
-                return false;
+    private static boolean isExifDataOnly(InputStream inputStream) {
+        try {
+            byte[] signatureCheckBytes = new byte[IDENTIFIER_EXIF_APP1.length];
+            inputStream.read(signatureCheckBytes);
+            if (Arrays.equals(signatureCheckBytes, IDENTIFIER_EXIF_APP1)) {
+                return true;
+            }
+        } catch (IOException e) {
+            if (DEBUG) {
+                Log.w(TAG,
+                        "Encountered error while checking whether input stream is Exif data only");
             }
         }
-        return true;
+        return false;
     }
 
     /**
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index fc05610..ef451ce 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -263,6 +263,8 @@
 
     boolean hasHapticChannels(in Uri uri);
 
+    boolean isCallScreeningModeSupported();
+
     // WARNING: read warning at top of file, new methods that need to be used by native
     // code via IAudioManager.h need to be added to the top section.
 }
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/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index b059bd3c..b7cb705 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -25,5 +25,7 @@
 oneway interface IMediaRouter2Manager {
     void notifyRouteSelected(String packageName, in MediaRoute2Info route);
     void notifyControlCategoriesChanged(String packageName, in List<String> categories);
-    void notifyProviderInfosUpdated(in List<MediaRoute2ProviderInfo> providers);
+    void notifyRoutesAdded(in List<MediaRoute2Info> routes);
+    void notifyRoutesRemoved(in List<MediaRoute2Info> routes);
+    void notifyRoutesChanged(in List<MediaRoute2Info> routes);
 }
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/MediaCodec.java b/media/java/android/media/MediaCodec.java
index b7a9ffe..d16a216 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1702,20 +1702,22 @@
                     break;
                 }
                 case EVENT_FRAME_RENDERED:
-                    synchronized (mListenerLock) {
-                        Map<String, Object> map = (Map<String, Object>)msg.obj;
-                        for (int i = 0; ; ++i) {
-                            Object mediaTimeUs = map.get(i + "-media-time-us");
-                            Object systemNano = map.get(i + "-system-nano");
-                            if (mediaTimeUs == null || systemNano == null
-                                    || mOnFrameRenderedListener == null) {
-                                break;
-                            }
-                            mOnFrameRenderedListener.onFrameRendered(
-                                    mCodec, (long)mediaTimeUs, (long)systemNano);
+                    Map<String, Object> map = (Map<String, Object>)msg.obj;
+                    for (int i = 0; ; ++i) {
+                        Object mediaTimeUs = map.get(i + "-media-time-us");
+                        Object systemNano = map.get(i + "-system-nano");
+                        OnFrameRenderedListener onFrameRenderedListener;
+                        synchronized (mListenerLock) {
+                            onFrameRenderedListener = mOnFrameRenderedListener;
                         }
-                        break;
+                        if (mediaTimeUs == null || systemNano == null
+                                || onFrameRenderedListener == null) {
+                            break;
+                        }
+                        onFrameRenderedListener.onFrameRendered(
+                                mCodec, (long)mediaTimeUs, (long)systemNano);
                     }
+                    break;
                 default:
                 {
                     break;
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index a08aec3..63657a6 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -748,12 +748,12 @@
 
     private Consumer<ListenerArgs> createOnEventListener(OnEventListener listener) {
         return args -> {
-            byte[] sessionId = args.parcel.createByteArray();
+            byte[] sessionId = args.sessionId;
             if (sessionId.length == 0) {
                 sessionId = null;
             }
-            byte[] data = args.parcel.createByteArray();
-            if (data.length == 0) {
+            byte[] data = args.data;
+            if (data != null && data.length == 0) {
                 data = null;
             }
 
@@ -765,10 +765,10 @@
     private Consumer<ListenerArgs> createOnKeyStatusChangeListener(
             OnKeyStatusChangeListener listener) {
         return args -> {
-            byte[] sessionId = args.parcel.createByteArray();
+            byte[] sessionId = args.sessionId;
             if (sessionId.length > 0) {
-                List<KeyStatus> keyStatusList = keyStatusListFromParcel(args.parcel);
-                boolean hasNewUsableKey = (args.parcel.readInt() != 0);
+                List<KeyStatus> keyStatusList = args.keyStatusList;
+                boolean hasNewUsableKey = args.hasNewUsableKey;
 
                 Log.i(TAG, "Drm key status changed");
                 listener.onKeyStatusChange(this, sessionId, keyStatusList, hasNewUsableKey);
@@ -779,9 +779,9 @@
     private Consumer<ListenerArgs> createOnExpirationUpdateListener(
             OnExpirationUpdateListener listener) {
         return args -> {
-            byte[] sessionId = args.parcel.createByteArray();
+            byte[] sessionId = args.sessionId;
             if (sessionId.length > 0) {
-                long expirationTime = args.parcel.readLong();
+                long expirationTime = args.expirationTime;
 
                 Log.i(TAG, "Drm key expiration update: " + expirationTime);
                 listener.onExpirationUpdate(this, sessionId, expirationTime);
@@ -792,22 +792,38 @@
     private Consumer<ListenerArgs> createOnSessionLostStateListener(
             OnSessionLostStateListener listener) {
         return args -> {
-            byte[] sessionId = args.parcel.createByteArray();
+            byte[] sessionId = args.sessionId;
             Log.i(TAG, "Drm session lost state event: ");
             listener.onSessionLostState(this, sessionId);
         };
     }
 
     private static class ListenerArgs {
-        private final Parcel parcel;
         private final int arg1;
         private final int arg2;
+        private final byte[] sessionId;
+        private final byte[] data;
+        private final long expirationTime;
+        private final List<KeyStatus> keyStatusList;
+        private final boolean hasNewUsableKey;
 
-        public ListenerArgs(Parcel parcel, int arg1, int arg2) {
-            this.parcel = parcel;
+        public ListenerArgs(
+                int arg1,
+                int arg2,
+                byte[] sessionId,
+                byte[] data,
+                long expirationTime,
+                List<KeyStatus> keyStatusList,
+                boolean hasNewUsableKey) {
             this.arg1 = arg1;
             this.arg2 = arg2;
+            this.sessionId = sessionId;
+            this.data = data;
+            this.expirationTime = expirationTime;
+            this.keyStatusList = keyStatusList;
+            this.hasNewUsableKey = hasNewUsableKey;
         }
+
     }
 
     private static class ListenerWithExecutor {
@@ -843,7 +859,9 @@
      * the cookie passed to native_setup().)
      */
     private static void postEventFromNative(@NonNull Object mediadrm_ref,
-            int what, int eventType, int extra, @Nullable Object obj)
+            int what, int eventType, int extra,
+            byte[] sessionId, byte[] data, long expirationTime,
+            List<KeyStatus> keyStatusList, boolean hasNewUsableKey)
     {
         MediaDrm md = (MediaDrm)((WeakReference<MediaDrm>)mediadrm_ref).get();
         if (md == null) {
@@ -861,10 +879,10 @@
                             Log.w(TAG, "MediaDrm went away with unhandled events");
                             return;
                         }
-                        if (obj != null && obj instanceof Parcel) {
-                            Parcel p = (Parcel)obj;
-                            listener.mConsumer.accept(new ListenerArgs(p, eventType, extra));
-                        }
+                        ListenerArgs args = new ListenerArgs(eventType, extra,
+                                sessionId, data, expirationTime,
+                                keyStatusList, hasNewUsableKey);
+                        listener.mConsumer.accept(args);
                     };
                     listener.mExecutor.execute(command);
                 }
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 cb6c126..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;
@@ -95,10 +96,16 @@
     private final String mPackageName;
     private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
 
+    //TODO: Use a lock for this to cover the below use case
+    // mRouter.setControlCategories(...);
+    // routes = mRouter.getRoutes();
+    // The current implementation returns empty list
     private volatile List<String> mControlCategories = Collections.emptyList();
 
     private MediaRoute2Info mSelectedRoute;
     @GuardedBy("sLock")
+    private MediaRoute2Info mSelectingRoute;
+    @GuardedBy("sLock")
     private Client mClient;
 
     final Handler mHandler;
@@ -202,6 +209,7 @@
                     } catch (RemoteException ex) {
                         Log.e(TAG, "Unable to unregister media router.", ex);
                     }
+                    //TODO: Clean up mRoutes. (onHandler?)
                     mClient = null;
                 }
             }
@@ -222,7 +230,6 @@
                 MediaRouter2.this, new ArrayList<>(controlCategories)));
     }
 
-
     /**
      * Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
      * known to the media router.
@@ -246,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);
             }
         }
     }
@@ -439,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<>();
 
@@ -471,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.
@@ -501,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 {
@@ -556,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/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 7e848a0..d56dd11 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -25,18 +25,16 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashSet;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -59,13 +57,11 @@
     private Client mClient;
     private final IMediaRouterService mMediaRouterService;
     final Handler mHandler;
-    final List<CallbackRecord> mCallbacks = new CopyOnWriteArrayList<>();
+    final List<CallbackRecord> mCallbackRecords = new CopyOnWriteArrayList<>();
 
-    @SuppressWarnings("WeakerAccess") /* synthetic access */
-    @NonNull
-    List<MediaRoute2ProviderInfo> mProviders = Collections.emptyList();
-    @NonNull
-    List<MediaRoute2Info> mRoutes = Collections.emptyList();
+    private final Object mRoutesLock = new Object();
+    @GuardedBy("mRoutesLock")
+    private final Map<String, MediaRoute2Info> mRoutes = new HashMap<>();
     @NonNull
     final ConcurrentMap<String, List<String>> mControlCategoryMap = new ConcurrentHashMap<>();
 
@@ -104,13 +100,13 @@
         Objects.requireNonNull(callback, "callback must not be null");
 
         CallbackRecord callbackRecord;
-        synchronized (mCallbacks) {
+        synchronized (mCallbackRecords) {
             if (findCallbackRecordIndexLocked(callback) >= 0) {
                 Log.w(TAG, "Ignoring to add the same callback twice.");
                 return;
             }
             callbackRecord = new CallbackRecord(executor, callback);
-            mCallbacks.add(callbackRecord);
+            mCallbackRecords.add(callbackRecord);
         }
 
         synchronized (sLock) {
@@ -136,32 +132,32 @@
     public void unregisterCallback(@NonNull Callback callback) {
         Objects.requireNonNull(callback, "callback must not be null");
 
-        synchronized (mCallbacks) {
+        synchronized (mCallbackRecords) {
             final int index = findCallbackRecordIndexLocked(callback);
             if (index < 0) {
                 Log.w(TAG, "Ignore removing unknown callback. " + callback);
                 return;
             }
-            mCallbacks.remove(index);
+            mCallbackRecords.remove(index);
             synchronized (sLock) {
-                if (mCallbacks.size() == 0 && mClient != null) {
+                if (mCallbackRecords.size() == 0 && mClient != null) {
                     try {
                         mMediaRouterService.unregisterManager(mClient);
                     } catch (RemoteException ex) {
                         Log.e(TAG, "Unable to unregister media router manager", ex);
                     }
-                    mClient.notifyProviderInfosUpdated(Collections.emptyList());
+                    //TODO: clear mRoutes?
                     mClient = null;
                 }
             }
         }
     }
 
-    @GuardedBy("mCallbacks")
+    @GuardedBy("mCallbackRecords")
     private int findCallbackRecordIndexLocked(Callback callback) {
-        final int count = mCallbacks.size();
+        final int count = mCallbackRecords.size();
         for (int i = 0; i < count; i++) {
-            if (mCallbacks.get(i).mCallback == callback) {
+            if (mCallbackRecords.get(i).mCallback == callback) {
                 return i;
             }
         }
@@ -184,11 +180,14 @@
             return Collections.emptyList();
         }
         List<MediaRoute2Info> routes = new ArrayList<>();
-        for (MediaRoute2Info route : mRoutes) {
-            if (route.supportsControlCategory(controlCategories)) {
-                routes.add(route);
+        synchronized (mRoutesLock) {
+            for (MediaRoute2Info route : mRoutes.values()) {
+                if (route.supportsControlCategory(controlCategories)) {
+                    routes.add(route);
+                }
             }
         }
+        //TODO: Should we cache this?
         return routes;
     }
 
@@ -282,136 +281,96 @@
         }
     }
 
-    int findProviderIndex(MediaRoute2ProviderInfo provider) {
-        final int count = mProviders.size();
-        for (int i = 0; i < count; i++) {
-            if (TextUtils.equals(mProviders.get(i).getUniqueId(), provider.getUniqueId())) {
-                return i;
+    void addRoutesOnHandler(List<MediaRoute2Info> routes) {
+        synchronized (mRoutesLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.put(route.getUniqueId(), route);
             }
         }
-        return -1;
+        if (routes.size() > 0) {
+            notifyRoutesAdded(routes);
+        }
     }
 
-    void updateProvider(@NonNull MediaRoute2ProviderInfo provider) {
-        if (provider == null || !provider.isValid()) {
-            Log.w(TAG, "Ignoring invalid provider : " + provider);
-            return;
-        }
-
-        final Collection<MediaRoute2Info> routes = provider.getRoutes();
-
-        final int index = findProviderIndex(provider);
-        if (index >= 0) {
-            final MediaRoute2ProviderInfo prevProvider = mProviders.get(index);
-            final Set<String> updatedRouteIds = new HashSet<>();
-            for (MediaRoute2Info routeInfo : routes) {
-                if (!routeInfo.isValid()) {
-                    Log.w(TAG, "Ignoring invalid route : " + routeInfo);
-                    continue;
-                }
-                final MediaRoute2Info prevRoute = prevProvider.getRoute(routeInfo.getId());
-                if (prevRoute == null) {
-                    notifyRouteAdded(routeInfo);
-                } else {
-                    if (!Objects.equals(prevRoute, routeInfo)) {
-                        notifyRouteChanged(routeInfo);
-                    }
-                    updatedRouteIds.add(routeInfo.getId());
-                }
-            }
-            final Collection<MediaRoute2Info> prevRoutes = prevProvider.getRoutes();
-
-            for (MediaRoute2Info prevRoute : prevRoutes) {
-                if (!updatedRouteIds.contains(prevRoute.getId())) {
-                    notifyRouteRemoved(prevRoute);
-                }
-            }
-        } else {
-            for (MediaRoute2Info routeInfo: routes) {
-                notifyRouteAdded(routeInfo);
+    void removeRoutesOnHandler(List<MediaRoute2Info> routes) {
+        synchronized (mRoutesLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.remove(route.getUniqueId());
             }
         }
+        if (routes.size() > 0) {
+            notifyRoutesRemoved(routes);
+        }
     }
 
-    void notifyRouteAdded(MediaRoute2Info routeInfo) {
-        for (CallbackRecord record : mCallbacks) {
+    void changeRoutesOnHandler(List<MediaRoute2Info> routes) {
+        synchronized (mRoutesLock) {
+            for (MediaRoute2Info route : routes) {
+                mRoutes.put(route.getUniqueId(), route);
+            }
+        }
+        if (routes.size() > 0) {
+            notifyRoutesChanged(routes);
+        }
+    }
+
+    private void notifyRoutesAdded(List<MediaRoute2Info> routes) {
+        for (CallbackRecord record: mCallbackRecords) {
             record.mExecutor.execute(
-                    () -> record.mCallback.onRouteAdded(routeInfo));
+                    () -> record.mCallback.onRoutesAdded(routes));
         }
     }
 
-    void notifyRouteChanged(MediaRoute2Info routeInfo) {
-        for (CallbackRecord record : mCallbacks) {
+    private void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
+        for (CallbackRecord record: mCallbackRecords) {
             record.mExecutor.execute(
-                    () -> record.mCallback.onRouteChanged(routeInfo));
+                    () -> record.mCallback.onRoutesRemoved(routes));
         }
     }
 
-    void notifyRouteRemoved(MediaRoute2Info routeInfo) {
-        for (CallbackRecord record : mCallbacks) {
+    private void notifyRoutesChanged(List<MediaRoute2Info> routes) {
+        for (CallbackRecord record: mCallbackRecords) {
             record.mExecutor.execute(
-                    () -> record.mCallback.onRouteRemoved(routeInfo));
+                    () -> record.mCallback.onRoutesChanged(routes));
         }
     }
 
-    void notifyRouteListChanged() {
-        for (CallbackRecord record: mCallbacks) {
-            record.mExecutor.execute(
-                    () -> record.mCallback.onRoutesChanged(mRoutes));
-        }
-    }
-
-    void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> providers) {
-        if (providers == null) {
-            Log.w(TAG, "Providers info is null.");
-            return;
-        }
-
-        ArrayList<MediaRoute2Info> routes = new ArrayList<>();
-
-        for (MediaRoute2ProviderInfo provider : providers) {
-            updateProvider(provider);
-            //TODO: Should we do this in updateProvider()?
-            routes.addAll(provider.getRoutes());
-        }
-        //TODO: Call notifyRouteRemoved for the routes of the removed providers.
-
-        //TODO: Filter invalid providers and invalid routes.
-        mProviders = providers;
-        mRoutes = routes;
-
-        //TODO: Call this when only the list is modified.
-        notifyRouteListChanged();
-    }
-
     void notifyRouteSelected(String packageName, MediaRoute2Info route) {
-        for (CallbackRecord record : mCallbacks) {
+        for (CallbackRecord record : mCallbackRecords) {
             record.mExecutor.execute(() -> record.mCallback.onRouteSelected(packageName, route));
         }
     }
 
     void updateControlCategories(String packageName, List<String> categories) {
         mControlCategoryMap.put(packageName, categories);
+        for (CallbackRecord record : mCallbackRecords) {
+            record.mExecutor.execute(
+                    () -> record.mCallback.onControlCategoriesChanged(packageName));
+        }
     }
 
     /**
      * Interface for receiving events about media routing changes.
      */
     public static class Callback {
-        /**
-         * Called when a route is added.
-         */
-        public void onRouteAdded(@NonNull MediaRoute2Info routeInfo) {}
 
         /**
-         * Called when a route is changed.
+         * Called when routes are added.
+         * @param routes the list of routes that have been added. It's never empty.
          */
-        public void onRouteChanged(@NonNull MediaRoute2Info routeInfo) {}
+        public void onRoutesAdded(@NonNull List<MediaRoute2Info> routes) {}
 
         /**
-         * Called when a route is removed.
+         * Called when routes are removed.
+         * @param routes the list of routes that have been removed. It's never empty.
          */
-        public void onRouteRemoved(@NonNull MediaRoute2Info routeInfo) {}
+        public void onRoutesRemoved(@NonNull List<MediaRoute2Info> routes) {}
+
+        /**
+         * Called when routes are changed.
+         * @param routes the list of routes that have been changed. It's never empty.
+         */
+        public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
 
         /**
          * Called when a route is selected for an application.
@@ -422,13 +381,13 @@
          */
         public void onRouteSelected(@NonNull String packageName, @Nullable MediaRoute2Info route) {}
 
-        /**
-         * Called when the list of routes is changed.
-         * A client may refresh available routes for each application.
-         */
-        public void onRoutesChanged(@NonNull List<MediaRoute2Info> routes) {}
 
-        //TODO: add onControlCategoriesChanged to notify available routes are changed
+        /**
+         * Called when the control categories of an app is changed.
+         *
+         * @param packageName the package name of the application
+         */
+        public void onControlCategoriesChanged(@NonNull String packageName) {}
     }
 
     final class CallbackRecord {
@@ -441,10 +400,12 @@
         }
 
         void notifyRoutes() {
-            mExecutor.execute(() -> mCallback.onRoutesChanged(mRoutes));
-            for (MediaRoute2Info routeInfo : mRoutes) {
-                mExecutor.execute(
-                        () -> mCallback.onRouteAdded(routeInfo));
+            List<MediaRoute2Info> routes;
+            synchronized (mRoutesLock) {
+                routes = new ArrayList<>(mRoutes.values());
+            }
+            if (routes.size() > 0) {
+                mExecutor.execute(() -> mCallback.onRoutesAdded(routes));
             }
         }
     }
@@ -463,9 +424,21 @@
         }
 
         @Override
-        public void notifyProviderInfosUpdated(List<MediaRoute2ProviderInfo> info) {
-            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyProviderInfosUpdated,
-                    MediaRouter2Manager.this, info));
+        public void notifyRoutesAdded(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::addRoutesOnHandler,
+                    MediaRouter2Manager.this, routes));
+        }
+
+        @Override
+        public void notifyRoutesRemoved(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::removeRoutesOnHandler,
+                    MediaRouter2Manager.this, routes));
+        }
+
+        @Override
+        public void notifyRoutesChanged(List<MediaRoute2Info> routes) {
+            mHandler.sendMessage(obtainMessage(MediaRouter2Manager::changeRoutesOnHandler,
+                    MediaRouter2Manager.this, routes));
         }
     }
 }
diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java
index 7eec8d9..8d85724 100644
--- a/media/java/android/media/MediaScannerConnection.java
+++ b/media/java/android/media/MediaScannerConnection.java
@@ -197,7 +197,7 @@
     private static Uri scanFileQuietly(ContentProviderClient client, File file) {
         Uri uri = null;
         try {
-            uri = MediaStore.scanFile(client, file);
+            uri = MediaStore.scanFile(client, file.getCanonicalFile());
             Log.d(TAG, "Scanned " + file + " to " + uri);
         } catch (Exception e) {
             Log.w(TAG, "Failed to scan " + file + ": " + e);
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index 7d68d02..c91325a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -17,6 +17,7 @@
 package android.media.tv.tuner;
 
 import android.annotation.Nullable;
+import android.media.tv.tuner.TunerConstants.DemuxPidType;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -35,6 +36,7 @@
     private static final int MSG_ON_FRONTEND_EVENT = 1;
     private static final int MSG_ON_FILTER_EVENT = 2;
     private static final int MSG_ON_FILTER_STATUS = 3;
+    private static final int MSG_ON_LNB_EVENT = 4;
 
     static {
         System.loadLibrary("media_tv_tuner");
@@ -45,6 +47,9 @@
     private Frontend mFrontend;
     private EventHandler mHandler;
 
+    private List<Integer> mLnbIds;
+    private Lnb mLnb;
+
     public Tuner() {
         nativeSetup();
     }
@@ -76,6 +81,12 @@
 
     private native Filter nativeOpenFilter(int type, int subType, int bufferSize);
 
+    private native List<Integer> nativeGetLnbIds();
+    private native Lnb nativeOpenLnbById(int id);
+
+    private native Descrambler nativeOpenDescrambler();
+
+    private native Dvr nativeOpenDvr(int type, int bufferSize);
 
     /**
      * Frontend Callback.
@@ -89,6 +100,16 @@
     }
 
     /**
+     * LNB Callback.
+     */
+    public interface LnbCallback {
+        /**
+         * Invoked when there is a LNB event.
+         */
+        void onEvent(int lnbEventType);
+    }
+
+    /**
      * Frontend Callback.
      */
     public interface FilterCallback {
@@ -98,6 +119,20 @@
         void onFilterStatus(int status);
     }
 
+    /**
+     * DVR Callback.
+     */
+    public interface DvrCallback {
+        /**
+         * Invoked when record status changed.
+         */
+        void onRecordStatus(int status);
+        /**
+         * Invoked when playback status changed.
+         */
+        void onPlaybackStatus(int status);
+    }
+
     @Nullable
     private EventHandler createEventHandler() {
         Looper looper;
@@ -129,6 +164,11 @@
                     }
                     break;
                 }
+                case MSG_ON_LNB_EVENT: {
+                    if (mLnb != null && mLnb.mCallback != null) {
+                        mLnb.mCallback.onEvent(msg.arg1);
+                    }
+                }
                 default:
                     // fall through
             }
@@ -193,6 +233,11 @@
         private long mNativeContext;
         private FilterCallback mCallback;
         int mId;
+
+        private native boolean nativeStartFilter();
+        private native boolean nativeStopFilter();
+        private native boolean nativeFlushFilter();
+
         private Filter(int id) {
             mId = id;
         }
@@ -203,6 +248,18 @@
                         mHandler.obtainMessage(MSG_ON_FILTER_STATUS, status, 0, this));
             }
         }
+
+        public boolean start() {
+            return nativeStartFilter();
+        }
+
+        public boolean stop() {
+            return nativeStopFilter();
+        }
+
+        public boolean flush() {
+            return nativeFlushFilter();
+        }
     }
 
     private Filter openFilter(int type, int subType, int bufferSize, FilterCallback cb) {
@@ -215,4 +272,103 @@
         }
         return filter;
     }
+
+    protected class Lnb {
+        private int mId;
+        private LnbCallback mCallback;
+
+        private Lnb(int id) {
+            mId = id;
+        }
+
+        public void setCallback(@Nullable LnbCallback callback) {
+            mCallback = callback;
+            if (mCallback == null) {
+                return;
+            }
+            if (mHandler == null) {
+                mHandler = createEventHandler();
+            }
+        }
+    }
+
+    private List<Integer> getLnbIds() {
+        mLnbIds = nativeGetLnbIds();
+        return mLnbIds;
+    }
+
+    private Lnb openLnbById(int id) {
+        if (mLnbIds == null) {
+            mLnbIds = getLnbIds();
+        }
+        if (!mLnbIds.contains(id)) {
+            return null;
+        }
+        mLnb = nativeOpenLnbById(id);
+        return mLnb;
+    }
+
+    private void onLnbEvent(int eventType) {
+        if (mHandler != null) {
+            mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LNB_EVENT, eventType, 0));
+        }
+    }
+
+    protected class Descrambler {
+        private long mNativeContext;
+
+        private native boolean nativeAddPid(int pidType, int pid, Filter filter);
+        private native boolean nativeRemovePid(int pidType, int pid, Filter filter);
+
+        private Descrambler() {}
+
+        private boolean addPid(@DemuxPidType int pidType, int pid, Filter filter) {
+            return nativeAddPid(pidType, pid, filter);
+        }
+
+        private boolean removePid(@DemuxPidType int pidType, int pid, Filter filter) {
+            return nativeRemovePid(pidType, pid, filter);
+        }
+
+    }
+
+    private Descrambler openDescrambler() {
+        Descrambler descrambler = nativeOpenDescrambler();
+        return descrambler;
+    }
+
+    // TODO: consider splitting Dvr to Playback and Recording
+    protected class Dvr {
+        private long mNativeContext;
+        private DvrCallback mCallback;
+
+        private native boolean nativeAttachFilter(Filter filter);
+        private native boolean nativeDetachFilter(Filter filter);
+        private native boolean nativeStartDvr();
+        private native boolean nativeStopDvr();
+        private native boolean nativeFlushDvr();
+
+        private Dvr() {}
+
+        public boolean attachFilter(Filter filter) {
+            return nativeAttachFilter(filter);
+        }
+        public boolean detachFilter(Filter filter) {
+            return nativeDetachFilter(filter);
+        }
+        public boolean start() {
+            return nativeStartDvr();
+        }
+        public boolean stop() {
+            return nativeStopDvr();
+        }
+        public boolean flush() {
+            return nativeFlushDvr();
+        }
+    }
+
+    private Dvr openDvr(int type, int bufferSize) {
+        Dvr dvr = nativeOpenDvr(type, bufferSize);
+        return dvr;
+    }
 }
diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java
index 411882e..01f9367 100644
--- a/media/java/android/media/tv/tuner/TunerConstants.java
+++ b/media/java/android/media/tv/tuner/TunerConstants.java
@@ -67,6 +67,14 @@
     public static final int DATA_FORMAT_ES = Constants.DataFormat.ES;
     public static final int DATA_FORMAT_SHV_TLV = Constants.DataFormat.SHV_TLV;
 
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({DEMUX_T_PID, DEMUX_MMPT_PID})
+    public @interface DemuxPidType {}
+
+    public static final int DEMUX_T_PID = 1;
+    public static final int DEMUX_MMPT_PID = 2;
+
     private TunerConstants() {
     }
 }
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 8f844d4..3833c6b 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -179,6 +179,10 @@
     jint kOfflineLicenseStateUnknown;
 } gOfflineLicenseStates;
 
+struct KeyStatusFields {
+    jmethodID init;
+    jclass classId;
+};
 
 struct fields_t {
     jfieldID context;
@@ -200,51 +204,21 @@
     jobject bundleCreator;
     jmethodID createFromParcelId;
     jclass parcelCreatorClassId;
+    KeyStatusFields keyStatus;
 };
 
 static fields_t gFields;
 
 namespace {
 
-// Helper function to convert a native PersistableBundle to a Java
-// PersistableBundle.
-jobject nativeToJavaPersistableBundle(JNIEnv *env, jobject thiz,
-                                      PersistableBundle* nativeBundle) {
-    if (env == NULL || thiz == NULL || nativeBundle == NULL) {
-        ALOGE("Unexpected NULL parmeter");
-        return NULL;
+jbyteArray hidlVectorToJByteArray(const hardware::hidl_vec<uint8_t> &vector) {
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    size_t length = vector.size();
+    jbyteArray result = env->NewByteArray(length);
+    if (result != NULL) {
+        env->SetByteArrayRegion(result, 0, length, reinterpret_cast<const jbyte *>(vector.data()));
     }
-
-    // Create a Java parcel with the native parcel data.
-    // Then create a new PersistableBundle with that parcel as a parameter.
-    jobject jParcel = android::createJavaParcelObject(env);
-    if (jParcel == NULL) {
-      ALOGE("Failed to create a Java Parcel.");
-      return NULL;
-    }
-
-    android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
-    if (nativeParcel == NULL) {
-      ALOGE("Failed to get the native Parcel.");
-      return NULL;
-    }
-
-    android::status_t result = nativeBundle->writeToParcel(nativeParcel);
-    nativeParcel->setDataPosition(0);
-    if (result != android::OK) {
-      ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
-      return NULL;
-    }
-
-    jobject newBundle = env->CallObjectMethod(gFields.bundleCreator,
-                                              gFields.createFromParcelId,
-                                              jParcel);
-    if (newBundle == NULL) {
-        ALOGE("Failed to create a new PersistableBundle "
-              "from the createFromParcel call.");
-    }
-
-    return newBundle;
+    return result;
 }
 
 }  // namespace anonymous
@@ -256,7 +230,7 @@
 public:
     JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
     ~JNIDrmListener();
-    virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
+    virtual void notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *arg = NULL);
 private:
     JNIDrmListener();
     jclass      mClass;     // Reference to MediaDrm class
@@ -290,7 +264,7 @@
 }
 
 void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
-                            const Parcel *obj)
+                            const ListenerArgs *args)
 {
     jint jwhat;
     jint jeventType = 0;
@@ -332,15 +306,11 @@
     }
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    if (obj && obj->dataSize() > 0) {
-        jobject jParcel = createJavaParcelObject(env);
-        if (jParcel != NULL) {
-            Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
-            nativeParcel->setData(obj->data(), obj->dataSize());
-            env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
-                    jwhat, jeventType, extra, jParcel);
-            env->DeleteLocalRef(jParcel);
-        }
+    if (args) {
+        env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
+                jwhat, jeventType, extra,
+                args->jSessionId, args->jData, args->jExpirationTime,
+                args->jKeyStatusList, args->jHasNewUsableKey);
     }
 
     if (env->ExceptionCheck()) {
@@ -511,7 +481,7 @@
     return OK;
 }
 
-void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
+void JDrm::notify(DrmPlugin::EventType eventType, int extra, const ListenerArgs *args) {
     sp<DrmListener> listener;
     mLock.lock();
     listener = mListener;
@@ -519,7 +489,7 @@
 
     if (listener != NULL) {
         Mutex::Autolock lock(mNotifyLock);
-        listener->notify(eventType, extra, obj);
+        listener->notify(eventType, extra, args);
     }
 }
 
@@ -527,34 +497,51 @@
         DrmPlugin::EventType eventType,
         const hardware::hidl_vec<uint8_t> &sessionId,
         const hardware::hidl_vec<uint8_t> &data) {
-    Parcel obj;
-    DrmUtils::WriteByteArray(obj, sessionId);
-    DrmUtils::WriteByteArray(obj, data);
-    notify(eventType, 0, &obj);
+    ListenerArgs args{
+        .jSessionId = hidlVectorToJByteArray(sessionId),
+        .jData = hidlVectorToJByteArray(data),
+    };
+    notify(eventType, 0, &args);
 }
 
 void JDrm::sendExpirationUpdate(
         const hardware::hidl_vec<uint8_t> &sessionId,
         int64_t expiryTimeInMS) {
-    Parcel obj;
-    DrmUtils::WriteExpirationUpdateToParcel(obj, sessionId, expiryTimeInMS);
-    notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &obj);
+    ListenerArgs args{
+        .jSessionId = hidlVectorToJByteArray(sessionId),
+        .jExpirationTime = expiryTimeInMS,
+    };
+    notify(DrmPlugin::kDrmPluginEventExpirationUpdate, 0, &args);
 }
 
 void JDrm::sendKeysChange(
         const hardware::hidl_vec<uint8_t> &sessionId,
         const std::vector<DrmKeyStatus> &keyStatusList,
         bool hasNewUsableKey) {
-    Parcel obj;
-    DrmUtils::WriteKeysChange(obj, sessionId, keyStatusList, hasNewUsableKey);
-    notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &obj);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass clazz = gFields.arraylistClassId;
+    jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
+    clazz = gFields.keyStatus.classId;
+    for (const auto &keyStatus : keyStatusList) {
+        jbyteArray jKeyId(hidlVectorToJByteArray(keyStatus.keyId));
+        jint jStatusCode(keyStatus.type);
+        jobject jKeyStatus = env->NewObject(clazz, gFields.keyStatus.init, jKeyId, jStatusCode);
+        env->CallBooleanMethod(arrayList, gFields.arraylist.add, jKeyStatus);
+    }
+    ListenerArgs args{
+        .jSessionId = hidlVectorToJByteArray(sessionId),
+        .jKeyStatusList = arrayList,
+        .jHasNewUsableKey = hasNewUsableKey,
+    };
+    notify(DrmPlugin::kDrmPluginEventKeysChange, 0, &args);
 }
 
 void JDrm::sendSessionLostState(
         const hardware::hidl_vec<uint8_t> &sessionId) {
-    Parcel obj;
-    DrmUtils::WriteByteArray(obj, sessionId);
-    notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &obj);
+    ListenerArgs args{
+        .jSessionId = hidlVectorToJByteArray(sessionId),
+    };
+    notify(DrmPlugin::kDrmPluginEventSessionLostState, 0, &args);
 }
 
 void JDrm::disconnect() {
@@ -753,7 +740,7 @@
     FIND_CLASS(clazz, "android/media/MediaDrm");
     GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "J");
     GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
-                         "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+                         "(Ljava/lang/Object;III[B[BJLjava/util/List;Z)V");
 
     jfieldID field;
     GET_STATIC_FIELD_ID(field, clazz, "EVENT_PROVISION_REQUIRED", "I");
@@ -913,6 +900,10 @@
     gSessionExceptionErrorCodes.kErrorUnknown = env->GetStaticIntField(clazz, field);
     GET_STATIC_FIELD_ID(field, clazz, "ERROR_RESOURCE_CONTENTION", "I");
     gSessionExceptionErrorCodes.kResourceContention = env->GetStaticIntField(clazz, field);
+
+    FIND_CLASS(clazz, "android/media/MediaDrm$KeyStatus");
+    gFields.keyStatus.classId = static_cast<jclass>(env->NewGlobalRef(clazz));
+    GET_METHOD_ID(gFields.keyStatus.init, clazz, "<init>", "([BI)V");
 }
 
 static void android_media_MediaDrm_native_setup(
@@ -1904,7 +1895,7 @@
         return (jobject) NULL;
     }
 
-    return nativeToJavaPersistableBundle(env, thiz, &metrics);
+    return MediaMetricsJNI::nativeToJavaPersistableBundle(env, &metrics);
 }
 
 static jbyteArray android_media_MediaDrm_signRSANative(
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 37d9e07..b1f544c 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -26,16 +26,28 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+namespace {
+
+struct ListenerArgs {
+    jbyteArray jSessionId;
+    jbyteArray jData;
+    jlong jExpirationTime;
+    jobject jKeyStatusList;
+    jboolean jHasNewUsableKey;
+};
+
+}
+
 namespace android {
 
 class DrmListener: virtual public RefBase
 {
 public:
     virtual void notify(DrmPlugin::EventType eventType, int extra,
-                        const Parcel *obj) = 0;
+                        const ListenerArgs *args) = 0;
 };
 
-struct JDrm : public BnDrmClient {
+struct JDrm : public IDrmClient {
     static status_t IsCryptoSchemeSupported(const uint8_t uuid[16],
                                             const String8 &mimeType,
                                             DrmPlugin::SecurityLevel level,
@@ -81,7 +93,7 @@
     static sp<IDrm> MakeDrm();
     static sp<IDrm> MakeDrm(const uint8_t uuid[16], const String8 &appPackageName);
 
-    void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
+    void notify(DrmPlugin::EventType, int extra, const ListenerArgs *args);
 
     DISALLOW_EVIL_CONSTRUCTORS(JDrm);
 };
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index bc4bceb..a5c62cb 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -22,7 +22,7 @@
 #include <assert.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
-#include <SkBitmap.h>
+#include <android/graphics/bitmap.h>
 #include <media/IMediaHTTPService.h>
 #include <media/mediametadataretriever.h>
 #include <media/mediascanner.h>
@@ -36,8 +36,6 @@
 #include "android_media_Streams.h"
 #include "android_util_Binder.h"
 
-#include "android/graphics/GraphicsJNI.h"
-
 using namespace android;
 
 struct fields_t {
@@ -45,8 +43,6 @@
     jclass bitmapClazz;  // Must be a global ref
     jmethodID createBitmapMethod;
     jmethodID createScaledBitmapMethod;
-    jclass configClazz;  // Must be a global ref
-    jmethodID createConfigMethod;
     jclass bitmapParamsClazz; // Must be a global ref
     jfieldID inPreferredConfig;
     jfieldID outActualConfig;
@@ -263,7 +259,7 @@
 
 static jobject getBitmapFromVideoFrame(
         JNIEnv *env, VideoFrame *videoFrame, jint dst_width, jint dst_height,
-        SkColorType outColorType) {
+        AndroidBitmapFormat outColorType) {
     ALOGV("getBitmapFromVideoFrame: dimension = %dx%d, displaySize = %dx%d, bytes = %d",
             videoFrame->mWidth,
             videoFrame->mHeight,
@@ -271,11 +267,7 @@
             videoFrame->mDisplayHeight,
             videoFrame->mSize);
 
-    ScopedLocalRef<jobject> config(env,
-            env->CallStaticObjectMethod(
-                    fields.configClazz,
-                    fields.createConfigMethod,
-                    GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
+    ScopedLocalRef<jobject> config(env, ABitmapConfig_getConfigFromFormat(env, outColorType));
 
     uint32_t width, height, displayWidth, displayHeight;
     bool swapWidthAndHeight = false;
@@ -306,10 +298,9 @@
         return NULL;
     }
 
-    SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jBitmap, &bitmap);
+    graphics::Bitmap bitmap(env, jBitmap);
 
-    if (outColorType == kRGB_565_SkColorType) {
+    if (outColorType == ANDROID_BITMAP_FORMAT_RGB_565) {
         rotate((uint16_t*)bitmap.getPixels(),
                (uint16_t*)((char*)videoFrame + sizeof(VideoFrame)),
                videoFrame->mWidth,
@@ -350,37 +341,26 @@
     return jBitmap;
 }
 
-static int getColorFormat(JNIEnv *env, jobject options,
-        int defaultPreferred = HAL_PIXEL_FORMAT_RGBA_8888) {
+static AndroidBitmapFormat getColorFormat(JNIEnv *env, jobject options,
+        AndroidBitmapFormat defaultPreferred = ANDROID_BITMAP_FORMAT_RGBA_8888) {
     if (options == NULL) {
         return defaultPreferred;
     }
 
     ScopedLocalRef<jobject> inConfig(env, env->GetObjectField(options, fields.inPreferredConfig));
-    SkColorType prefColorType = GraphicsJNI::getNativeBitmapColorType(env, inConfig.get());
+    AndroidBitmapFormat format = ABitmapConfig_getFormatFromConfig(env, inConfig.get());
 
-    if (prefColorType == kRGB_565_SkColorType) {
-        return HAL_PIXEL_FORMAT_RGB_565;
+    if (format == ANDROID_BITMAP_FORMAT_RGB_565) {
+        return ANDROID_BITMAP_FORMAT_RGB_565;
     }
-    return HAL_PIXEL_FORMAT_RGBA_8888;
+    return ANDROID_BITMAP_FORMAT_RGBA_8888;
 }
 
-static SkColorType setOutColorType(JNIEnv *env, int colorFormat, jobject options) {
-    SkColorType outColorType = kN32_SkColorType;
-    if (colorFormat == HAL_PIXEL_FORMAT_RGB_565) {
-        outColorType = kRGB_565_SkColorType;
-    }
-
+static void setOutConfig(JNIEnv *env, jobject options, AndroidBitmapFormat colorFormat) {
     if (options != NULL) {
-        ScopedLocalRef<jobject> config(env,
-                env->CallStaticObjectMethod(
-                        fields.configClazz,
-                        fields.createConfigMethod,
-                        GraphicsJNI::colorTypeToLegacyBitmapConfig(outColorType)));
-
+        ScopedLocalRef<jobject> config(env, ABitmapConfig_getConfigFromFormat(env, colorFormat));
         env->SetObjectField(options, fields.outActualConfig, config.get());
     }
-    return outColorType;
 }
 
 static jobject android_media_MediaMetadataRetriever_getFrameAtTime(
@@ -394,9 +374,9 @@
         jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
         return NULL;
     }
-    // For getFrameAtTime family of calls, default to HAL_PIXEL_FORMAT_RGB_565
+    // For getFrameAtTime family of calls, default to ANDROID_BITMAP_FORMAT_RGB_565
     // to keep the behavior consistent with older releases
-    int colorFormat = getColorFormat(env, params, HAL_PIXEL_FORMAT_RGB_565);
+    AndroidBitmapFormat colorFormat = getColorFormat(env, params, ANDROID_BITMAP_FORMAT_RGB_565);
 
     // Call native method to retrieve a video frame
     VideoFrame *videoFrame = NULL;
@@ -413,9 +393,8 @@
         return NULL;
     }
 
-    SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
-    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
+    setOutConfig(env, params, colorFormat);
+    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, colorFormat);
 }
 
 static jobject android_media_MediaMetadataRetriever_getImageAtIndex(
@@ -428,7 +407,7 @@
         return NULL;
     }
 
-    int colorFormat = getColorFormat(env, params);
+    AndroidBitmapFormat colorFormat = getColorFormat(env, params);
 
     // Call native method to retrieve an image
     VideoFrame *videoFrame = NULL;
@@ -445,9 +424,8 @@
         return NULL;
     }
 
-    SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
-    return getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+    setOutConfig(env, params, colorFormat);
+    return getBitmapFromVideoFrame(env, videoFrame, -1, -1, colorFormat);
 }
 
 static jobject android_media_MediaMetadataRetriever_getThumbnailImageAtIndex(
@@ -461,7 +439,7 @@
         return NULL;
     }
 
-    int colorFormat = getColorFormat(env, params);
+    AndroidBitmapFormat colorFormat = getColorFormat(env, params);
     jint dst_width = -1, dst_height = -1;
 
     // Call native method to retrieve an image
@@ -508,9 +486,8 @@
     // thumbnails extracted by BitmapFactory APIs.
     videoFrame->mRotationAngle = 0;
 
-    SkColorType outColorType = setOutColorType(env, colorFormat, params);
-
-    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, outColorType);
+    setOutConfig(env, params, colorFormat);
+    return getBitmapFromVideoFrame(env, videoFrame, dst_width, dst_height, colorFormat);
 }
 
 static jobject android_media_MediaMetadataRetriever_getFrameAtIndex(
@@ -532,8 +509,8 @@
         return NULL;
     }
 
-    int colorFormat = getColorFormat(env, params);
-    SkColorType outColorType = setOutColorType(env, colorFormat, params);
+    AndroidBitmapFormat colorFormat = getColorFormat(env, params);
+    setOutConfig(env, params, colorFormat);
     size_t i = 0;
     for (; i < numFrames; i++) {
         sp<IMemory> frame = retriever->getFrameAtIndex(frameIndex + i, colorFormat);
@@ -546,7 +523,7 @@
         //       Either document why it is safe in this case or address the
         //       issue (e.g. by copying).
         VideoFrame *videoFrame = static_cast<VideoFrame *>(frame->unsecurePointer());
-        jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, outColorType);
+        jobject bitmapObj = getBitmapFromVideoFrame(env, videoFrame, -1, -1, colorFormat);
         env->CallBooleanMethod(arrayList, fields.arrayListAdd, bitmapObj);
         env->DeleteLocalRef(bitmapObj);
     }
@@ -671,21 +648,6 @@
         return;
     }
 
-    clazz.reset(env->FindClass("android/graphics/Bitmap$Config"));
-    if (clazz.get() == NULL) {
-        return;
-    }
-    fields.configClazz = (jclass) env->NewGlobalRef(clazz.get());
-    if (fields.configClazz == NULL) {
-        return;
-    }
-    fields.createConfigMethod =
-            env->GetStaticMethodID(fields.configClazz, "nativeToConfig",
-                    "(I)Landroid/graphics/Bitmap$Config;");
-    if (fields.createConfigMethod == NULL) {
-        return;
-    }
-
     clazz.reset(env->FindClass("android/media/MediaMetadataRetriever$BitmapParams"));
     if (clazz.get() == NULL) {
         return;
diff --git a/media/jni/android_media_MediaMetricsJNI.cpp b/media/jni/android_media_MediaMetricsJNI.cpp
index e7487c3..5ddfcfc 100644
--- a/media/jni/android_media_MediaMetricsJNI.cpp
+++ b/media/jni/android_media_MediaMetricsJNI.cpp
@@ -20,7 +20,9 @@
 #include <nativehelper/JNIHelp.h>
 
 #include "android_media_MediaMetricsJNI.h"
+#include "android_os_Parcel.h"
 #include <media/MediaAnalyticsItem.h>
+#include <binder/Parcel.h>
 
 
 // This source file is compiled and linked into:
@@ -223,5 +225,72 @@
     return NULL;
 }
 
+// Helper function to convert a native PersistableBundle to a Java
+// PersistableBundle.
+jobject MediaMetricsJNI::nativeToJavaPersistableBundle(JNIEnv *env,
+                                                       os::PersistableBundle* nativeBundle) {
+    if (env == NULL || nativeBundle == NULL) {
+        ALOGE("Unexpected NULL parmeter");
+        return NULL;
+    }
+
+    // Create a Java parcel with the native parcel data.
+    // Then create a new PersistableBundle with that parcel as a parameter.
+    jobject jParcel = android::createJavaParcelObject(env);
+    if (jParcel == NULL) {
+      ALOGE("Failed to create a Java Parcel.");
+      return NULL;
+    }
+
+    android::Parcel* nativeParcel = android::parcelForJavaObject(env, jParcel);
+    if (nativeParcel == NULL) {
+      ALOGE("Failed to get the native Parcel.");
+      return NULL;
+    }
+
+    android::status_t result = nativeBundle->writeToParcel(nativeParcel);
+    nativeParcel->setDataPosition(0);
+    if (result != android::OK) {
+      ALOGE("Failed to write nativeBundle to Parcel: %d.", result);
+      return NULL;
+    }
+
+#define STATIC_INIT_JNI(T, obj, method, globalref, ...) \
+    static T obj{};\
+    if (obj == NULL) { \
+        obj = method(__VA_ARGS__); \
+        if (obj == NULL) { \
+            ALOGE("%s can't find " #obj, __func__); \
+            return NULL; \
+        } else { \
+            obj = globalref; \
+        }\
+    } \
+
+    STATIC_INIT_JNI(jclass, clazzBundle, env->FindClass,
+            static_cast<jclass>(env->NewGlobalRef(clazzBundle)),
+            "android/os/PersistableBundle");
+    STATIC_INIT_JNI(jfieldID, bundleCreatorId, env->GetStaticFieldID,
+            bundleCreatorId,
+            clazzBundle, "CREATOR", "Landroid/os/Parcelable$Creator;");
+    STATIC_INIT_JNI(jobject, bundleCreator, env->GetStaticObjectField,
+            env->NewGlobalRef(bundleCreator),
+            clazzBundle, bundleCreatorId);
+    STATIC_INIT_JNI(jclass, clazzCreator, env->FindClass,
+            static_cast<jclass>(env->NewGlobalRef(clazzCreator)),
+            "android/os/Parcelable$Creator");
+    STATIC_INIT_JNI(jmethodID, createFromParcelId, env->GetMethodID,
+            createFromParcelId,
+            clazzCreator, "createFromParcel", "(Landroid/os/Parcel;)Ljava/lang/Object;");
+
+    jobject newBundle = env->CallObjectMethod(bundleCreator, createFromParcelId, jParcel);
+    if (newBundle == NULL) {
+        ALOGE("Failed to create a new PersistableBundle "
+              "from the createFromParcel call.");
+    }
+
+    return newBundle;
+}
+
 };  // namespace android
 
diff --git a/media/jni/android_media_MediaMetricsJNI.h b/media/jni/android_media_MediaMetricsJNI.h
index a10780f..e879da0 100644
--- a/media/jni/android_media_MediaMetricsJNI.h
+++ b/media/jni/android_media_MediaMetricsJNI.h
@@ -20,6 +20,7 @@
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
 #include <media/MediaAnalyticsItem.h>
+#include <binder/PersistableBundle.h>
 
 // Copeid from core/jni/ (libandroid_runtime.so)
 namespace android {
@@ -28,6 +29,7 @@
 public:
     static jobject writeMetricsToBundle(JNIEnv* env, MediaAnalyticsItem *item, jobject mybundle);
     static jobject writeAttributesToBundle(JNIEnv* env, jobject mybundle, char *buffer, size_t length);
+    static jobject nativeToJavaPersistableBundle(JNIEnv*, os::PersistableBundle*);
 };
 
 };  // namespace android
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 2640572..f5202fc 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -28,22 +28,64 @@
 using ::android::hardware::Void;
 using ::android::hardware::hidl_vec;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
+using ::android::hardware::tv::tuner::V1_0::DemuxTpid;
 using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 struct fields_t {
-    jfieldID context;
+    jfieldID tunerContext;
     jfieldID filterContext;
+    jfieldID descramblerContext;
+    jfieldID dvrContext;
     jmethodID frontendInitID;
     jmethodID filterInitID;
+    jmethodID dvrInitID;
     jmethodID onFrontendEventID;
     jmethodID onFilterStatusID;
+    jmethodID lnbInitID;
+    jmethodID onLnbEventID;
+    jmethodID descramblerInitID;
 };
 
 static fields_t gFields;
 
 namespace android {
+/////////////// LnbCallback ///////////////////////
+LnbCallback::LnbCallback(jweak tunerObj, LnbId id) : mObject(tunerObj), mId(id) {}
+
+Return<void> LnbCallback::onEvent(LnbEventType lnbEventType) {
+    ALOGD("LnbCallback::onEvent, type=%d", lnbEventType);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(
+            mObject,
+            gFields.onLnbEventID,
+            (jint)lnbEventType);
+    return Void();
+}
+Return<void> LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& /*diseqcMessage*/) {
+    ALOGD("LnbCallback::onDiseqcMessage");
+    return Void();
+}
+
+/////////////// DvrCallback ///////////////////////
+Return<void> DvrCallback::onRecordStatus(RecordStatus /*status*/) {
+    ALOGD("DvrCallback::onRecordStatus");
+    return Void();
+}
+
+Return<void> DvrCallback::onPlaybackStatus(PlaybackStatus /*status*/) {
+    ALOGD("DvrCallback::onPlaybackStatus");
+    return Void();
+}
+
+void DvrCallback::setDvr(const jobject dvr) {
+    ALOGD("FilterCallback::setDvr");
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    mDvr = env->NewWeakGlobalRef(dvr);
+}
+
 /////////////// FilterCallback ///////////////////////
 //TODO: implement filter callback
 Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& /*filterEvent*/) {
@@ -175,6 +217,52 @@
             (jint) jId);
 }
 
+jobject JTuner::getLnbIds() {
+    ALOGD("JTuner::getLnbIds()");
+    mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
+        mLnbIds = lnbIds;
+    });
+    if (mLnbIds.size() == 0) {
+        ALOGW("Lnb isn't available");
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jclass arrayListClazz = env->FindClass("java/util/ArrayList");
+    jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
+    jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
+
+    jclass integerClazz = env->FindClass("java/lang/Integer");
+    jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
+
+    for (int i=0; i < mLnbIds.size(); i++) {
+       jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]);
+       env->CallBooleanMethod(obj, arrayListAdd, idObj);
+    }
+    return obj;
+}
+
+jobject JTuner::openLnbById(int id) {
+    sp<ILnb> lnbSp;
+    mTuner->openLnbById(id, [&](Result, const sp<ILnb>& lnb) {
+        lnbSp = lnb;
+    });
+    if (lnbSp == nullptr) {
+        ALOGE("Failed to open lnb");
+        return NULL;
+    }
+    mLnb = lnbSp;
+    sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+    mLnb->setCallback(lnbCb);
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    return env->NewObject(
+            env->FindClass("android/media/tv/tuner/Tuner$Lnb"),
+            gFields.lnbInitID,
+            mObject,
+            id);
+}
+
 bool JTuner::openDemux() {
     if (mTuner == nullptr) {
         return false;
@@ -193,6 +281,33 @@
     return true;
 }
 
+jobject JTuner::openDescrambler() {
+    ALOGD("JTuner::openDescrambler");
+    if (mTuner == nullptr) {
+        return NULL;
+    }
+    sp<IDescrambler> descramblerSp;
+    mTuner->openDescrambler([&](Result, const sp<IDescrambler>& descrambler) {
+        descramblerSp = descrambler;
+    });
+
+    if (descramblerSp == NULL) {
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jobject descramblerObj =
+            env->NewObject(
+                    env->FindClass("android/media/tv/tuner/Tuner$Descrambler"),
+                    gFields.descramblerInitID,
+                    mObject);
+
+    descramblerSp->incStrong(descramblerObj);
+    env->SetLongField(descramblerObj, gFields.descramblerContext, (jlong)descramblerSp.get());
+
+    return descramblerObj;
+}
+
 jobject JTuner::openFilter(DemuxFilterType type, int bufferSize) {
     if (mDemux == NULL) {
         if (!openDemux()) {
@@ -231,6 +346,39 @@
     return filterObj;
 }
 
+jobject JTuner::openDvr(DvrType type, int bufferSize) {
+    ALOGD("JTuner::openDvr");
+    if (mDemux == NULL) {
+        if (!openDemux()) {
+            return NULL;
+        }
+    }
+    sp<IDvr> dvrSp;
+    sp<DvrCallback> callback = new DvrCallback();
+    mDemux->openDvr(type, bufferSize, callback,
+            [&](Result, const sp<IDvr>& dvr) {
+                dvrSp = dvr;
+            });
+
+    if (dvrSp == NULL) {
+        return NULL;
+    }
+
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    jobject dvrObj =
+            env->NewObject(
+                    env->FindClass("android/media/tv/tuner/Tuner$Dvr"),
+                    gFields.dvrInitID,
+                    mObject);
+
+    dvrSp->incStrong(dvrObj);
+    env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
+
+    callback->setDvr(dvrObj);
+
+    return dvrObj;
+}
+
 }  // namespace android
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -238,7 +386,7 @@
 using namespace android;
 
 static sp<JTuner> setTuner(JNIEnv *env, jobject thiz, const sp<JTuner> &tuner) {
-    sp<JTuner> old = (JTuner *)env->GetLongField(thiz, gFields.context);
+    sp<JTuner> old = (JTuner *)env->GetLongField(thiz, gFields.tunerContext);
 
     if (tuner != NULL) {
         tuner->incStrong(thiz);
@@ -246,38 +394,71 @@
     if (old != NULL) {
         old->decStrong(thiz);
     }
-    env->SetLongField(thiz, gFields.context, (jlong)tuner.get());
+    env->SetLongField(thiz, gFields.tunerContext, (jlong)tuner.get());
 
     return old;
 }
 
 static sp<JTuner> getTuner(JNIEnv *env, jobject thiz) {
-    return (JTuner *)env->GetLongField(thiz, gFields.context);
+    return (JTuner *)env->GetLongField(thiz, gFields.tunerContext);
+}
+
+static sp<IDescrambler> getDescrambler(JNIEnv *env, jobject descrambler) {
+    return (IDescrambler *)env->GetLongField(descrambler, gFields.descramblerContext);
+}
+
+static DemuxPid getDemuxPid(int pidType, int pid) {
+    DemuxPid demuxPid;
+    if ((int)pidType == 1) {
+        demuxPid.tPid(static_cast<DemuxTpid>(pid));
+    } else if ((int)pidType == 2) {
+        demuxPid.mmtpPid(static_cast<DemuxMmtpPid>(pid));
+    }
+    return demuxPid;
 }
 
 static sp<IFilter> getFilter(JNIEnv *env, jobject filter) {
     return (IFilter *)env->GetLongField(filter, gFields.filterContext);
 }
 
+static sp<IDvr> getDvr(JNIEnv *env, jobject dvr) {
+    return (IDvr *)env->GetLongField(dvr, gFields.dvrContext);
+}
+
 static void android_media_tv_Tuner_native_init(JNIEnv *env) {
     jclass clazz = env->FindClass("android/media/tv/tuner/Tuner");
     CHECK(clazz != NULL);
 
-    gFields.context = env->GetFieldID(clazz, "mNativeContext", "J");
-    CHECK(gFields.context != NULL);
+    gFields.tunerContext = env->GetFieldID(clazz, "mNativeContext", "J");
+    CHECK(gFields.tunerContext != NULL);
 
     gFields.onFrontendEventID = env->GetMethodID(clazz, "onFrontendEvent", "(I)V");
 
+    gFields.onLnbEventID = env->GetMethodID(clazz, "onLnbEvent", "(I)V");
+
     jclass frontendClazz = env->FindClass("android/media/tv/tuner/Tuner$Frontend");
     gFields.frontendInitID =
             env->GetMethodID(frontendClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
 
+    jclass lnbClazz = env->FindClass("android/media/tv/tuner/Tuner$Lnb");
+    gFields.lnbInitID =
+            env->GetMethodID(lnbClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
+
     jclass filterClazz = env->FindClass("android/media/tv/tuner/Tuner$Filter");
     gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
     gFields.filterInitID =
             env->GetMethodID(filterClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;I)V");
     gFields.onFilterStatusID =
             env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+
+    jclass descramblerClazz = env->FindClass("android/media/tv/tuner/Tuner$Descrambler");
+    gFields.descramblerContext = env->GetFieldID(descramblerClazz, "mNativeContext", "J");
+    gFields.descramblerInitID =
+            env->GetMethodID(descramblerClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
+
+    jclass dvrClazz = env->FindClass("android/media/tv/tuner/Tuner$Dvr");
+    gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
+    gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "(Landroid/media/tv/tuner/Tuner;)V");
 }
 
 static void android_media_tv_Tuner_native_setup(JNIEnv *env, jobject thiz) {
@@ -295,6 +476,16 @@
     return tuner->openFrontendById(id);
 }
 
+static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->getLnbIds();
+}
+
+static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, jint id) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openLnbById(id);
+}
+
 static jobject android_media_tv_Tuner_open_filter(
         JNIEnv *env, jobject thiz, jint type, jint subType, jint bufferSize) {
     sp<JTuner> tuner = getTuner(env, thiz);
@@ -308,7 +499,113 @@
     return tuner->openFilter(filterType, bufferSize);
 }
 
-static const JNINativeMethod gMethods[] = {
+static bool android_media_tv_Tuner_start_filter(JNIEnv *env, jobject filter) {
+    sp<IFilter> filterSp = getFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed to start filter: filter not found");
+        return false;
+    }
+    return filterSp->start() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_stop_filter(JNIEnv *env, jobject filter) {
+    sp<IFilter> filterSp = getFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed to stop filter: filter not found");
+        return false;
+    }
+    return filterSp->stop() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_flush_filter(JNIEnv *env, jobject filter) {
+    sp<IFilter> filterSp = getFilter(env, filter);
+    if (filterSp == NULL) {
+        ALOGD("Failed to flush filter: filter not found");
+        return false;
+    }
+    return filterSp->flush() == Result::SUCCESS;
+}
+
+static jobject android_media_tv_Tuner_open_descrambler(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openDescrambler();
+}
+
+static bool android_media_tv_Tuner_add_pid(
+        JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
+    sp<IDescrambler> descramblerSp = getDescrambler(env, descrambler);
+    if (descramblerSp == NULL) {
+        return false;
+    }
+    sp<IFilter> filterSp = getFilter(env, filter);
+    Result result = descramblerSp->addPid(getDemuxPid((int)pidType, (int)pid), filterSp);
+    return result == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_remove_pid(
+        JNIEnv *env, jobject descrambler, jint pidType, jint pid, jobject filter) {
+    sp<IDescrambler> descramblerSp = getDescrambler(env, descrambler);
+    if (descramblerSp == NULL) {
+        return false;
+    }
+    sp<IFilter> filterSp = getFilter(env, filter);
+    Result result = descramblerSp->removePid(getDemuxPid((int)pidType, (int)pid), filterSp);
+    return result == Result::SUCCESS;
+}
+
+static jobject android_media_tv_Tuner_open_dvr(JNIEnv *env, jobject thiz, jint type, jint bufferSize) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->openDvr(static_cast<DvrType>(type), bufferSize);
+}
+
+static bool android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) {
+    sp<IDvr> dvrSp = getDvr(env, dvr);
+    sp<IFilter> filterSp = getFilter(env, filter);
+    if (dvrSp == NULL || filterSp == NULL) {
+        return false;
+    }
+    Result result = dvrSp->attachFilter(filterSp);
+    return result == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_detach_filter(JNIEnv *env, jobject dvr, jobject filter) {
+    sp<IDvr> dvrSp = getDvr(env, dvr);
+    sp<IFilter> filterSp = getFilter(env, filter);
+    if (dvrSp == NULL || filterSp == NULL) {
+        return false;
+    }
+    Result result = dvrSp->detachFilter(filterSp);
+    return result == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
+    sp<IDvr> dvrSp = getDvr(env, dvr);
+    if (dvrSp == NULL) {
+        ALOGD("Failed to start dvr: dvr not found");
+        return false;
+    }
+    return dvrSp->start() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_stop_dvr(JNIEnv *env, jobject dvr) {
+    sp<IDvr> dvrSp = getDvr(env, dvr);
+    if (dvrSp == NULL) {
+        ALOGD("Failed to stop dvr: dvr not found");
+        return false;
+    }
+    return dvrSp->stop() == Result::SUCCESS;
+}
+
+static bool android_media_tv_Tuner_flush_dvr(JNIEnv *env, jobject dvr) {
+    sp<IDvr> dvrSp = getDvr(env, dvr);
+    if (dvrSp == NULL) {
+        ALOGD("Failed to flush dvr: dvr not found");
+        return false;
+    }
+    return dvrSp->flush() == Result::SUCCESS;
+}
+
+static const JNINativeMethod gTunerMethods[] = {
     { "nativeInit", "()V", (void *)android_media_tv_Tuner_native_init },
     { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup },
     { "nativeGetFrontendIds", "()Ljava/util/List;",
@@ -317,11 +614,67 @@
             (void *)android_media_tv_Tuner_open_frontend_by_id },
     { "nativeOpenFilter", "(III)Landroid/media/tv/tuner/Tuner$Filter;",
             (void *)android_media_tv_Tuner_open_filter },
+    { "nativeGetLnbIds", "()Ljava/util/List;",
+            (void *)android_media_tv_Tuner_get_lnb_ids },
+    { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Tuner$Lnb;",
+            (void *)android_media_tv_Tuner_open_lnb_by_id },
+    { "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Tuner$Descrambler;",
+            (void *)android_media_tv_Tuner_open_descrambler },
+    { "nativeOpenDvr", "(II)Landroid/media/tv/tuner/Tuner$Dvr;",
+            (void *)android_media_tv_Tuner_open_dvr },
 };
 
-static int register_android_media_tv_Tuner(JNIEnv *env) {
-    return AndroidRuntime::registerNativeMethods(
-            env, "android/media/tv/tuner/Tuner", gMethods, NELEM(gMethods));
+static const JNINativeMethod gFilterMethods[] = {
+    { "nativeStartFilter", "()Z", (void *)android_media_tv_Tuner_start_filter },
+    { "nativeStopFilter", "()Z", (void *)android_media_tv_Tuner_stop_filter },
+    { "nativeFlushFilter", "()Z", (void *)android_media_tv_Tuner_flush_filter },
+};
+
+static const JNINativeMethod gDescramblerMethods[] = {
+    { "nativeAddPid", "(IILandroid/media/tv/tuner/Tuner$Filter;)Z",
+            (void *)android_media_tv_Tuner_add_pid },
+    { "nativeRemovePid", "(IILandroid/media/tv/tuner/Tuner$Filter;)Z",
+            (void *)android_media_tv_Tuner_remove_pid },
+};
+
+static const JNINativeMethod gDvrMethods[] = {
+    { "nativeAttachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
+            (void *)android_media_tv_Tuner_attach_filter },
+    { "nativeDetachFilter", "(Landroid/media/tv/tuner/Tuner$Filter;)Z",
+            (void *)android_media_tv_Tuner_detach_filter },
+    { "nativeStartDvr", "()Z", (void *)android_media_tv_Tuner_start_dvr },
+    { "nativeStopDvr", "()Z", (void *)android_media_tv_Tuner_stop_dvr },
+    { "nativeFlushDvr", "()Z", (void *)android_media_tv_Tuner_flush_dvr },
+};
+
+static bool register_android_media_tv_Tuner(JNIEnv *env) {
+    if (AndroidRuntime::registerNativeMethods(
+            env, "android/media/tv/tuner/Tuner", gTunerMethods, NELEM(gTunerMethods)) != JNI_OK) {
+        ALOGE("Failed to register tuner native methods");
+        return false;
+    }
+    if (AndroidRuntime::registerNativeMethods(
+            env, "android/media/tv/tuner/Tuner$Filter",
+            gFilterMethods,
+            NELEM(gFilterMethods)) != JNI_OK) {
+        ALOGE("Failed to register filter native methods");
+        return false;
+    }
+    if (AndroidRuntime::registerNativeMethods(
+            env, "android/media/tv/tuner/Tuner$Descrambler",
+            gDescramblerMethods,
+            NELEM(gDescramblerMethods)) != JNI_OK) {
+        ALOGE("Failed to register descrambler native methods");
+        return false;
+    }
+    if (AndroidRuntime::registerNativeMethods(
+            env, "android/media/tv/tuner/Tuner$Dvr",
+            gDvrMethods,
+            NELEM(gDvrMethods)) != JNI_OK) {
+        ALOGE("Failed to register dvr native methods");
+        return false;
+    }
+    return true;
 }
 
 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
@@ -335,7 +688,7 @@
     }
     assert(env != NULL);
 
-    if (register_android_media_tv_Tuner(env) != JNI_OK) {
+    if (!register_android_media_tv_Tuner(env)) {
         ALOGE("ERROR: Tuner native registration failed\n");
         return result;
     }
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index ab48761..3bf6ec8 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -28,19 +28,47 @@
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
 using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using ::android::hardware::tv::tuner::V1_0::DemuxPid;
+using ::android::hardware::tv::tuner::V1_0::DvrType;
 using ::android::hardware::tv::tuner::V1_0::FrontendEventType;
 using ::android::hardware::tv::tuner::V1_0::FrontendId;
 using ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
 using ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
 using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDescrambler;
+using ::android::hardware::tv::tuner::V1_0::IDvr;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
 using ::android::hardware::tv::tuner::V1_0::IFilter;
 using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
 using ::android::hardware::tv::tuner::V1_0::IFrontend;
 using ::android::hardware::tv::tuner::V1_0::IFrontendCallback;
+using ::android::hardware::tv::tuner::V1_0::ILnb;
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
 using ::android::hardware::tv::tuner::V1_0::ITuner;
+using ::android::hardware::tv::tuner::V1_0::LnbEventType;
+using ::android::hardware::tv::tuner::V1_0::LnbId;
+using ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using ::android::hardware::tv::tuner::V1_0::RecordStatus;
 
 namespace android {
 
+struct LnbCallback : public ILnbCallback {
+    LnbCallback(jweak tunerObj, LnbId id);
+    virtual Return<void> onEvent(LnbEventType lnbEventType);
+    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+    jweak mObject;
+    LnbId mId;
+};
+
+struct DvrCallback : public IDvrCallback {
+    virtual Return<void> onRecordStatus(RecordStatus status);
+    virtual Return<void> onPlaybackStatus(PlaybackStatus status);
+
+    void setDvr(const jobject dvr);
+private:
+    jweak mDvr;
+};
+
 struct FilterCallback : public IFilterCallback {
     virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent);
     virtual Return<void> onFilterStatus(const DemuxFilterStatus status);
@@ -67,7 +95,12 @@
     sp<ITuner> getTunerService();
     jobject getFrontendIds();
     jobject openFrontendById(int id);
+    jobject getLnbIds();
+    jobject openLnbById(int id);
     jobject openFilter(DemuxFilterType type, int bufferSize);
+    jobject openDescrambler();
+    jobject openDvr(DvrType type, int bufferSize);
+
 protected:
     bool openDemux();
     virtual ~JTuner();
@@ -78,6 +111,8 @@
     static sp<ITuner> mTuner;
     hidl_vec<FrontendId> mFeIds;
     sp<IFrontend> mFe;
+    hidl_vec<LnbId> mLnbIds;
+    sp<ILnb> mLnb;
     sp<IDemux> mDemux;
     int mDemuxId;
 };
diff --git a/media/lib/tvremote/OWNERS b/media/lib/tvremote/OWNERS
new file mode 100644
index 0000000..81d52e1
--- /dev/null
+++ b/media/lib/tvremote/OWNERS
@@ -0,0 +1,2 @@
+nutka@google.com
+skill@google.com
diff --git a/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
index 35322ad..0bf0f97 100644
--- a/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
+++ b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
@@ -19,18 +19,18 @@
 import android.content.Context;
 import android.media.tv.ITvRemoteProvider;
 import android.media.tv.ITvRemoteServiceInput;
-import android.os.Handler;
 import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
 
+import java.util.LinkedList;
+
 /**
  * Base class for emote providers implemented in unbundled service.
  * <p/>
  * This object is not thread safe.  It is only intended to be accessed on the
  * {@link Context#getMainLooper main looper thread} of an application.
+ * The callback {@link #onInputBridgeConnected()} may be called from a different thread.
  * </p><p>
  * IMPORTANT: This class is effectively a system API for unbundled emote service, and
  * must remain API stable. See README.txt in the root of this package for more information.
@@ -50,11 +50,9 @@
 
     private static final String TAG = "TvRemoteProvider";
     private static final boolean DEBUG_KEYS = false;
-    private static final int MSG_SET_SERVICE_INPUT = 1;
-    private static final int MSG_SEND_INPUTBRIDGE_CONNECTED = 2;
     private final Context mContext;
     private final ProviderStub mStub;
-    private final ProviderHandler mHandler;
+    private final LinkedList<Runnable> mOpenBridgeRunnables;
     private ITvRemoteServiceInput mRemoteServiceInput;
 
     /**
@@ -67,7 +65,7 @@
     public TvRemoteProvider(Context context) {
         mContext = context.getApplicationContext();
         mStub = new ProviderStub();
-        mHandler = new ProviderHandler(mContext.getMainLooper());
+        mOpenBridgeRunnables = new LinkedList<Runnable>();
     }
 
     /**
@@ -77,7 +75,6 @@
         return mContext;
     }
 
-
     /**
      * Gets the Binder associated with the provider.
      * <p>
@@ -105,7 +102,11 @@
      * @param tvServiceInput sink defined in framework service
      */
     private void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
-        mRemoteServiceInput = tvServiceInput;
+        synchronized (mOpenBridgeRunnables) {
+            mRemoteServiceInput = tvServiceInput;
+        }
+        mOpenBridgeRunnables.forEach(Runnable::run);
+        mOpenBridgeRunnables.clear();
     }
 
     /**
@@ -125,8 +126,25 @@
      */
     public void openRemoteInputBridge(IBinder token, String name, int width, int height,
                                       int maxPointers) throws RuntimeException {
+        synchronized (mOpenBridgeRunnables) {
+            if (mRemoteServiceInput == null) {
+                Log.d(TAG, "Delaying openRemoteInputBridge() for " + name);
+
+                mOpenBridgeRunnables.add(() -> {
+                    try {
+                        mRemoteServiceInput.openInputBridge(
+                                token, name, width, height, maxPointers);
+                        Log.d(TAG, "Delayed openRemoteInputBridge() for " + name + ": success");
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Delayed openRemoteInputBridge() for " + name + ": failure", re);
+                    }
+                });
+                return;
+            }
+        }
         try {
             mRemoteServiceInput.openInputBridge(token, name, width, height, maxPointers);
+            Log.d(TAG, "openRemoteInputBridge() for " + name + ": success");
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
@@ -271,33 +289,12 @@
     private final class ProviderStub extends ITvRemoteProvider.Stub {
         @Override
         public void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
-            mHandler.obtainMessage(MSG_SET_SERVICE_INPUT, tvServiceInput).sendToTarget();
+            TvRemoteProvider.this.setRemoteServiceInputSink(tvServiceInput);
         }
 
         @Override
         public void onInputBridgeConnected(IBinder token) {
-            mHandler.obtainMessage(MSG_SEND_INPUTBRIDGE_CONNECTED, 0, 0,
-                    (IBinder) token).sendToTarget();
-        }
-    }
-
-    private final class ProviderHandler extends Handler {
-        public ProviderHandler(Looper looper) {
-            super(looper, null, true);
-        }
-
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_SET_SERVICE_INPUT: {
-                    setRemoteServiceInputSink((ITvRemoteServiceInput) msg.obj);
-                    break;
-                }
-                case MSG_SEND_INPUTBRIDGE_CONNECTED: {
-                    onInputBridgeConnected((IBinder) msg.obj);
-                    break;
-                }
-            }
+            TvRemoteProvider.this.onInputBridgeConnected(token);
         }
     }
 }
diff --git a/media/lib/tvremote/tests/Android.bp b/media/lib/tvremote/tests/Android.bp
new file mode 100644
index 0000000..f00eed0
--- /dev/null
+++ b/media/lib/tvremote/tests/Android.bp
@@ -0,0 +1,15 @@
+android_test {
+    name: "TvRemoteTests",
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+        "com.android.media.tv.remoteprovider",
+    ],
+    static_libs: [
+        "mockito-target-minus-junit4",
+    ],
+    platform_apis: true,
+    certificate: "platform",
+    privileged: true,
+}
diff --git a/media/lib/tvremote/tests/AndroidManifest.xml b/media/lib/tvremote/tests/AndroidManifest.xml
new file mode 100644
index 0000000..4f843f7
--- /dev/null
+++ b/media/lib/tvremote/tests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.media.tv.remoteprovider">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+             android:targetPackage="com.android.media.tv.remoteprovider"
+             android:label="Tests for TV Remote"/>
+</manifest>
diff --git a/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
new file mode 100644
index 0000000..c9ce5613
--- /dev/null
+++ b/media/lib/tvremote/tests/src/com/android/media/tv/remoteprovider/TvRemoteProviderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.tv.remoteprovider;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.content.Context;
+import android.media.tv.ITvRemoteProvider;
+import android.media.tv.ITvRemoteServiceInput;
+import android.os.Binder;
+import android.os.IBinder;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+
+public class TvRemoteProviderTest extends AndroidTestCase {
+    private static final String TAG = TvRemoteProviderTest.class.getSimpleName();
+
+    @SmallTest
+    public void testOpenRemoteInputBridge() throws Exception {
+        Binder tokenA = new Binder();
+        Binder tokenB = new Binder();
+        Binder tokenC = new Binder();
+
+        class LocalTvRemoteProvider extends TvRemoteProvider {
+            private final ArrayList<IBinder> mTokens = new ArrayList<IBinder>();
+
+            LocalTvRemoteProvider(Context context) {
+                super(context);
+            }
+
+            @Override
+            public void onInputBridgeConnected(IBinder token) {
+                mTokens.add(token);
+            }
+
+            public boolean verifyTokens() {
+                return mTokens.size() == 3
+                    && mTokens.contains(tokenA)
+                    && mTokens.contains(tokenB)
+                    && mTokens.contains(tokenC);
+            }
+        }
+
+        LocalTvRemoteProvider tvProvider = new LocalTvRemoteProvider(getContext());
+        ITvRemoteProvider binder = (ITvRemoteProvider) tvProvider.getBinder();
+
+        ITvRemoteServiceInput tvServiceInput = mock(ITvRemoteServiceInput.class);
+        doAnswer((i) -> {
+            binder.onInputBridgeConnected(i.getArgument(0));
+            return null;
+        }).when(tvServiceInput).openInputBridge(any(), any(), anyInt(), anyInt(), anyInt());
+
+        tvProvider.openRemoteInputBridge(tokenA, "A", 1, 1, 1);
+        tvProvider.openRemoteInputBridge(tokenB, "B", 1, 1, 1);
+        binder.setRemoteServiceInputSink(tvServiceInput);
+        tvProvider.openRemoteInputBridge(tokenC, "C", 1, 1, 1);
+
+        verify(tvServiceInput).openInputBridge(tokenA, "A", 1, 1, 1);
+        verify(tvServiceInput).openInputBridge(tokenB, "B", 1, 1, 1);
+        verify(tvServiceInput).openInputBridge(tokenC, "C", 1, 1, 1);
+        verifyNoMoreInteractions(tvServiceInput);
+
+        assertTrue(tvProvider.verifyTokens());
+    }
+}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 87a59df..f979fdd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -284,11 +284,12 @@
             ICameraDeviceCallbacks dummyCallbacks = new DummyCameraDeviceCallbacks();
 
             String clientPackageName = getContext().getPackageName();
+            String clientFeatureId = getContext().getFeatureId();
 
             ICameraDeviceUser cameraUser =
                     mUtils.getCameraService().connectDevice(
                         dummyCallbacks, String.valueOf(cameraId),
-                        clientPackageName,
+                        clientPackageName, clientFeatureId,
                         ICameraService.USE_CALLING_UID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 30561ba..466c5f4 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -238,11 +238,12 @@
         ICameraDeviceCallbacks.Stub dummyCallbacks = new DummyCameraDeviceCallbacks();
 
         String clientPackageName = getContext().getPackageName();
+        String clientFeatureId = getContext().getFeatureId();
 
         mMockCb = spy(dummyCallbacks);
 
         mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
-                clientPackageName, ICameraService.USE_CALLING_UID);
+                clientPackageName, clientFeatureId, ICameraService.USE_CALLING_UID);
         assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index acf8998..240e7d1 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -31,7 +32,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.MediaRoute2Info;
-import android.media.MediaRouter;
 import android.media.MediaRouter2;
 import android.media.MediaRouter2Manager;
 import android.support.test.InstrumentationRegistry;
@@ -52,6 +52,7 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
+import java.util.function.Predicate;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -85,7 +86,6 @@
 
     private Context mContext;
     private MediaRouter2Manager mManager;
-    private MediaRouter mRouter;
     private MediaRouter2 mRouter2;
     private Executor mExecutor;
     private String mPackageName;
@@ -103,7 +103,6 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mManager = MediaRouter2Manager.getInstance(mContext);
-        mRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE);
         mRouter2 = MediaRouter2.getInstance(mContext);
         //TODO: If we need to support thread pool executors, change this to thread pool executor.
         mExecutor = Executors.newSingleThreadExecutor();
@@ -124,64 +123,58 @@
         assertNotEquals(routeInfo1, routeInfo3);
     }
 
-    //TODO: Test onRouteChanged when it's properly implemented.
     @Test
-    public void testRouteAdded() {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
+    public void testOnRoutesAdded() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRoutesAdded(List<MediaRoute2Info> routes) {
+                assertTrue(routes.size() > 0);
+                for (MediaRoute2Info route : routes) {
+                    if (route.getId().equals(ROUTE_ID1) && route.getName().equals(ROUTE_NAME1)) {
+                        latch.countDown();
+                    }
+                }
+            }
+        };
+        mManager.registerCallback(mExecutor, callback);
 
-        mManager.registerCallback(mExecutor, mockCallback);
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-        verify(mockCallback, timeout(TIMEOUT_MS)).onRouteAdded(argThat(
-                (MediaRoute2Info info) ->
-                        info.getId().equals(ROUTE_ID1) && info.getName().equals(ROUTE_NAME1)));
-        mManager.unregisterCallback(mockCallback);
+        mManager.unregisterCallback(callback);
     }
 
-    //TODO: Recover this test when media router 2 is finalized.
-    public void testRouteRemoved() {
+    @Test
+    public void testOnRoutesRemoved() throws Exception {
         MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
         mManager.registerCallback(mExecutor, mockCallback);
 
-        MediaRouter2.Callback mockRouterCallback = mock(MediaRouter2.Callback.class);
+        MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
+        mRouter2.registerCallback(mExecutor, routerCallback);
+
+        Map<String, MediaRoute2Info> routes =
+                waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
+
+        CountDownLatch latch = new CountDownLatch(1);
+        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRoutesRemoved(List<MediaRoute2Info> routes) {
+                assertTrue(routes.size() > 0);
+                for (MediaRoute2Info route : routes) {
+                    if (route.getId().equals(ROUTE_ID2) && route.getName().equals(ROUTE_NAME2)) {
+                        latch.countDown();
+                    }
+                }
+            }
+        };
+        mManager.registerCallback(mExecutor, callback);
 
         //TODO: Figure out a more proper way to test.
         // (Control requests shouldn't be used in this way.)
-        mRouter2.setControlCategories(CONTROL_CATEGORIES_ALL);
-        mRouter2.registerCallback(mExecutor, mockRouterCallback);
-        mRouter2.sendControlRequest(
-                new MediaRoute2Info.Builder(ROUTE_ID2, ROUTE_NAME2).build(),
-                new Intent(ACTION_REMOVE_ROUTE));
-        mRouter2.unregisterCallback(mockRouterCallback);
+        mRouter2.sendControlRequest(routes.get(ROUTE_ID2), new Intent(ACTION_REMOVE_ROUTE));
+        assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-        verify(mockCallback, timeout(TIMEOUT_MS)).onRouteRemoved(argThat(
-                (MediaRoute2Info info) ->
-                        info.getId().equals(ROUTE_ID2) && info.getName().equals(ROUTE_NAME2)));
-        mManager.unregisterCallback(mockCallback);
-    }
-
-    /**
-     * Tests if we get proper routes for application that has special control category.
-     */
-    @Test
-    public void testControlCategoryWithMediaRouter() throws Exception {
-        MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class);
-        mManager.registerCallback(mExecutor, mockCallback);
-
-        MediaRouter.Callback mockRouterCallback = mock(MediaRouter.Callback.class);
-
-        mRouter.setControlCategories(CONTROL_CATEGORIES_SPECIAL);
-        mRouter.addCallback(MediaRouter.ROUTE_TYPE_USER, mockRouterCallback);
-
-        verify(mockCallback, timeout(TIMEOUT_MS))
-                .onRoutesChanged(argThat(routes -> routes.size() > 0));
-
-        Map<String, MediaRoute2Info> routes =
-                createRouteMap(mManager.getAvailableRoutes(mPackageName));
-
-        Assert.assertEquals(1, routes.size());
-        Assert.assertNotNull(routes.get(ROUTE_ID_SPECIAL_CATEGORY));
-
-        mRouter.removeCallback(mockRouterCallback);
+        mRouter2.unregisterCallback(routerCallback);
         mManager.unregisterCallback(mockCallback);
     }
 
@@ -233,7 +226,8 @@
 
         mManager.selectRoute(mPackageName, routeToSelect);
         verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteAdded(argThat(route -> route.equals(routeToSelect)));
+                .onRouteSelected(eq(mPackageName),
+                        argThat(route -> route != null && route.equals(routeToSelect)));
 
         mRouter2.unregisterCallback(routerCallback);
         mManager.unregisterCallback(managerCallback);
@@ -244,31 +238,28 @@
      */
     @Test
     public void testSingleProviderSelect() throws Exception {
-        MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
         MediaRouter2.Callback routerCallback = mock(MediaRouter2.Callback.class);
 
-        mManager.registerCallback(mExecutor, managerCallback);
         mRouter2.registerCallback(mExecutor, routerCallback);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
 
-        mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1));
-        verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID1, routeInfo.getId())
-                        && TextUtils.equals(routeInfo.getClientPackageName(), mPackageName)));
+        awaitOnRouteChangedManager(
+                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)),
+                ROUTE_ID1,
+                route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
-        mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2));
-        verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId())
-                        && TextUtils.equals(routeInfo.getClientPackageName(), mPackageName)));
+        awaitOnRouteChangedManager(
+                () -> mManager.selectRoute(mPackageName, routes.get(ROUTE_ID2)),
+                ROUTE_ID2,
+                route -> TextUtils.equals(route.getClientPackageName(), mPackageName));
 
-        mManager.unselectRoute(mPackageName);
-        verify(managerCallback, timeout(TIMEOUT_MS))
-                .onRouteChanged(argThat(routeInfo -> TextUtils.equals(ROUTE_ID2, routeInfo.getId())
-                        && TextUtils.equals(routeInfo.getClientPackageName(), null)));
+        awaitOnRouteChangedManager(
+                () -> mManager.unselectRoute(mPackageName),
+                ROUTE_ID2,
+                route -> TextUtils.equals(route.getClientPackageName(), null));
 
         mRouter2.unregisterCallback(routerCallback);
-        mManager.unregisterCallback(managerCallback);
     }
 
     @Test
@@ -279,52 +270,39 @@
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
 
-        CountDownLatch latch1 = new CountDownLatch(1);
-        MediaRouter2.Callback callback1 =
-                createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME,
-                        originalVolume + deltaVolume, latch1);
-        mRouter2.registerCallback(mExecutor, callback1);
-        mRouter2.requestUpdateVolume(volRoute, deltaVolume);
-        assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        mRouter2.unregisterCallback(callback1);
+        awaitOnRouteChanged(
+                () -> mRouter2.requestUpdateVolume(volRoute, deltaVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume + deltaVolume));
 
-        CountDownLatch latch2 = new CountDownLatch(1);
-        MediaRouter2.Callback callback2 =
-                createVolumeChangeCallback(ROUTE_ID_VARIABLE_VOLUME, originalVolume, latch2);
-        mRouter2.registerCallback(mExecutor, callback2);
-        mRouter2.requestSetVolume(volRoute, originalVolume);
-        assertTrue(latch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        mRouter2.unregisterCallback(callback1);
+        awaitOnRouteChanged(
+                () -> mRouter2.requestSetVolume(volRoute, originalVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume));
     }
 
     @Test
     public void testControlVolumeWithManager() throws Exception {
-        MediaRouter2Manager.Callback managerCallback = mock(MediaRouter2Manager.Callback.class);
         MediaRouter2.Callback mockCallback = mock(MediaRouter2.Callback.class);
 
-        mManager.registerCallback(mExecutor, managerCallback);
         mRouter2.registerCallback(mExecutor, mockCallback);
         Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(CONTROL_CATEGORIES_ALL);
 
         MediaRoute2Info volRoute = routes.get(ROUTE_ID_VARIABLE_VOLUME);
         int originalVolume = volRoute.getVolume();
         int deltaVolume = (originalVolume == volRoute.getVolumeMax() ? -1 : 1);
-        int targetVolume = originalVolume + deltaVolume;
 
-        mManager.requestSetVolume(volRoute, targetVolume);
-        verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
-                .onRouteChanged(argThat(route ->
-                        route.getId().equals(volRoute.getId())
-                                && route.getVolume() == targetVolume));
+        awaitOnRouteChangedManager(
+                () -> mManager.requestUpdateVolume(volRoute, deltaVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume + deltaVolume));
 
-        mManager.requestUpdateVolume(volRoute, -deltaVolume);
-        verify(managerCallback, timeout(TIMEOUT_MS).atLeastOnce())
-                .onRouteChanged(argThat(route ->
-                        route.getId().equals(volRoute.getId())
-                                && route.getVolume() == originalVolume));
+        awaitOnRouteChangedManager(
+                () -> mManager.requestSetVolume(volRoute, originalVolume),
+                ROUTE_ID_VARIABLE_VOLUME,
+                (route -> route.getVolume() == originalVolume));
 
         mRouter2.unregisterCallback(mockCallback);
-        mManager.unregisterCallback(managerCallback);
     }
 
     @Test
@@ -363,25 +341,29 @@
 
     Map<String, MediaRoute2Info> waitAndGetRoutesWithManager(List<String> controlCategories)
             throws Exception {
-        CountDownLatch latch = new CountDownLatch(1);
+        CountDownLatch latch = new CountDownLatch(2);
 
-        // Dummy callback is required to send control category info.
+        // A dummy callback is required to send control category info.
         MediaRouter2.Callback routerCallback = new MediaRouter2.Callback();
         MediaRouter2Manager.Callback managerCallback = new MediaRouter2Manager.Callback() {
             @Override
-            public void onRoutesChanged(List<MediaRoute2Info> routes) {
+            public void onRoutesAdded(List<MediaRoute2Info> routes) {
                 if (routes.size() > 0) {
                     latch.countDown();
                 }
             }
+            @Override
+            public void onControlCategoriesChanged(String packageName) {
+                if (TextUtils.equals(mPackageName, packageName)) {
+                    latch.countDown();
+                }
+            }
         };
         mManager.registerCallback(mExecutor, managerCallback);
         mRouter2.setControlCategories(controlCategories);
         mRouter2.registerCallback(mExecutor, routerCallback);
         try {
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-            //TODO: currently this returns empty list occasionally.
-            //Maybe due to control category is not set yet
             return createRouteMap(mManager.getAvailableRoutes(mPackageName));
         } finally {
             mRouter2.unregisterCallback(routerCallback);
@@ -389,18 +371,46 @@
         }
     }
 
-    MediaRouter2.Callback createVolumeChangeCallback(String routeId,
-            int targetVolume, CountDownLatch latch) {
+    void awaitOnRouteChanged(Runnable task, String routeId,
+            Predicate<MediaRoute2Info> predicate) throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
         MediaRouter2.Callback callback = new MediaRouter2.Callback() {
             @Override
             public void onRoutesChanged(List<MediaRoute2Info> changed) {
-                MediaRoute2Info volRoute = createRouteMap(changed).get(routeId);
-                if (volRoute != null && volRoute.getVolume() == targetVolume) {
+                MediaRoute2Info route = createRouteMap(changed).get(routeId);
+                if (route != null && predicate.test(route)) {
                     latch.countDown();
                 }
             }
         };
-        return callback;
+        mRouter2.registerCallback(mExecutor, callback);
+        try {
+            new Thread(task).start();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterCallback(callback);
+        }
+    }
+
+    void awaitOnRouteChangedManager(Runnable task, String routeId,
+            Predicate<MediaRoute2Info> predicate) throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        MediaRouter2Manager.Callback callback = new MediaRouter2Manager.Callback() {
+            @Override
+            public void onRoutesChanged(List<MediaRoute2Info> changed) {
+                MediaRoute2Info route = createRouteMap(changed).get(routeId);
+                if (route != null && predicate.test(route)) {
+                    latch.countDown();
+                }
+            }
+        };
+        mManager.registerCallback(mExecutor, callback);
+        try {
+            new Thread(task).start();
+            assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mManager.unregisterCallback(callback);
+        }
     }
 
     // Helper for getting routes easily
diff --git a/mime/java-res/android.mime.types b/mime/java-res/android.mime.types
index ce022a8..cb04d92 100644
--- a/mime/java-res/android.mime.types
+++ b/mime/java-res/android.mime.types
@@ -73,6 +73,7 @@
 ?audio/3gpp 3gpp 3ga
 ?audio/aac-adts aac
 ?audio/ac3 ac3 a52
+?audio/amr amr
 ?audio/imelody imy
 ?audio/midi rtttl xmf
 ?audio/mobile-xmf mxmf
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 91297b0..9d93c9b 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -36,7 +36,6 @@
 
     srcs: [
         "asset_manager.cpp",
-        "choreographer.cpp",
         "configuration.cpp",
         "hardware_buffer_jni.cpp",
         "input.cpp",
@@ -80,7 +79,7 @@
         "libarect",
     ],
 
-    whole_static_libs: ["libnativewindow"],
+    whole_static_libs: ["libnativedisplay", "libnativewindow"],
 
     export_static_lib_headers: ["libarect"],
 
@@ -142,4 +141,4 @@
         "aidl/com/android/internal/compat/IPlatformCompatNative.aidl",
     ],
     path: "aidl",
-}
\ No newline at end of file
+}
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
deleted file mode 100644
index 63e0734..0000000
--- a/native/android/choreographer.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Choreographer"
-//#define LOG_NDEBUG 0
-
-#include <cinttypes>
-#include <queue>
-#include <thread>
-
-#include <android/choreographer.h>
-#include <androidfw/DisplayEventDispatcher.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <utils/Looper.h>
-#include <utils/Mutex.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-static inline const char* toString(bool value) {
-    return value ? "true" : "false";
-}
-
-struct FrameCallback {
-    AChoreographer_frameCallback callback;
-    AChoreographer_frameCallback64 callback64;
-    void* data;
-    nsecs_t dueTime;
-
-    inline bool operator<(const FrameCallback& rhs) const {
-        // Note that this is intentionally flipped because we want callbacks due sooner to be at
-        // the head of the queue
-        return dueTime > rhs.dueTime;
-    }
-};
-
-
-class Choreographer : public DisplayEventDispatcher, public MessageHandler {
-public:
-    void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
-                                  AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
-
-    enum {
-        MSG_SCHEDULE_CALLBACKS = 0,
-        MSG_SCHEDULE_VSYNC = 1
-    };
-    virtual void handleMessage(const Message& message) override;
-
-    static Choreographer* getForThread();
-
-protected:
-    virtual ~Choreographer() = default;
-
-private:
-    explicit Choreographer(const sp<Looper>& looper);
-    Choreographer(const Choreographer&) = delete;
-
-    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
-    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
-    void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                               int32_t configId) override;
-
-    void scheduleCallbacks();
-
-    // Protected by mLock
-    std::priority_queue<FrameCallback> mCallbacks;
-
-    mutable Mutex mLock;
-
-    const sp<Looper> mLooper;
-    const std::thread::id mThreadId;
-};
-
-
-static thread_local Choreographer* gChoreographer;
-Choreographer* Choreographer::getForThread() {
-    if (gChoreographer == nullptr) {
-        sp<Looper> looper = Looper::getForThread();
-        if (!looper.get()) {
-            ALOGW("No looper prepared for thread");
-            return nullptr;
-        }
-        gChoreographer = new Choreographer(looper);
-        status_t result = gChoreographer->initialize();
-        if (result != OK) {
-            ALOGW("Failed to initialize");
-            return nullptr;
-        }
-    }
-    return gChoreographer;
-}
-
-Choreographer::Choreographer(const sp<Looper>& looper) :
-    DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
-}
-
-void Choreographer::postFrameCallbackDelayed(
-        AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    FrameCallback callback{cb, cb64, data, now + delay};
-    {
-        AutoMutex _l{mLock};
-        mCallbacks.push(callback);
-    }
-    if (callback.dueTime <= now) {
-        if (std::this_thread::get_id() != mThreadId) {
-            Message m{MSG_SCHEDULE_VSYNC};
-            mLooper->sendMessage(this, m);
-        } else {
-            scheduleVsync();
-        }
-    } else {
-        Message m{MSG_SCHEDULE_CALLBACKS};
-        mLooper->sendMessageDelayed(delay, this, m);
-    }
-}
-
-void Choreographer::scheduleCallbacks() {
-    AutoMutex _{mLock};
-    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-    if (mCallbacks.top().dueTime <= now) {
-        ALOGV("choreographer %p ~ scheduling vsync", this);
-        scheduleVsync();
-        return;
-    }
-}
-
-// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
-// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
-// the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
-    std::vector<FrameCallback> callbacks{};
-    {
-        AutoMutex _l{mLock};
-        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
-        while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
-            callbacks.push_back(mCallbacks.top());
-            mCallbacks.pop();
-        }
-    }
-    for (const auto& cb : callbacks) {
-        if (cb.callback64 != nullptr) {
-            cb.callback64(timestamp, cb.data);
-        } else if (cb.callback != nullptr) {
-            cb.callback(timestamp, cb.data);
-        }
-    }
-}
-
-void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
-    ALOGV("choreographer %p ~ received hotplug event (displayId=%"
-            ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
-            this, displayId, toString(connected));
-}
-
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
-                                          int32_t configId) {
-    ALOGV("choreographer %p ~ received config changed event (displayId=%"
-            ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
-            this, displayId, toString(configId));
-}
-
-void Choreographer::handleMessage(const Message& message) {
-    switch (message.what) {
-    case MSG_SCHEDULE_CALLBACKS:
-        scheduleCallbacks();
-        break;
-    case MSG_SCHEDULE_VSYNC:
-        scheduleVsync();
-        break;
-    }
-}
-
-}
-
-/* Glue for the NDK interface */
-
-using android::Choreographer;
-
-static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* choreographer) {
-    return reinterpret_cast<Choreographer*>(choreographer);
-}
-
-static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) {
-    return reinterpret_cast<AChoreographer*>(choreographer);
-}
-
-AChoreographer* AChoreographer_getInstance() {
-    return Choreographer_to_AChoreographer(Choreographer::getForThread());
-}
-
-void AChoreographer_postFrameCallback(AChoreographer* choreographer,
-        AChoreographer_frameCallback callback, void* data) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            callback, nullptr, data, 0);
-}
-void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
-        AChoreographer_frameCallback callback, void* data, long delayMillis) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            callback, nullptr, data, ms2ns(delayMillis));
-}
-void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
-        AChoreographer_frameCallback64 callback, void* data) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            nullptr, callback, data, 0);
-}
-void AChoreographer_postFrameCallbackDelayed64(AChoreographer* choreographer,
-        AChoreographer_frameCallback64 callback, void* data, uint32_t delayMillis) {
-    AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
-            nullptr, callback, data, ms2ns(delayMillis));
-}
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/native/android/surface_texture.cpp b/native/android/surface_texture.cpp
index ced279277..3049ec1 100644
--- a/native/android/surface_texture.cpp
+++ b/native/android/surface_texture.cpp
@@ -23,25 +23,19 @@
 
 #include <gui/Surface.h>
 
+#include <gui/surfacetexture/surface_texture_platform.h>
+
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 
-#include "surfacetexture/SurfaceTexture.h"
-
 using namespace android;
 
-struct ASurfaceTexture {
-    sp<SurfaceTexture> consumer;
-    sp<IGraphicBufferProducer> producer;
-};
-
 ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) {
     if (!surfacetexture || !android_SurfaceTexture_isInstanceOf(env, surfacetexture)) {
         return nullptr;
     }
-    ASurfaceTexture* ast = new ASurfaceTexture;
-    ast->consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
-    ast->producer = SurfaceTexture_getProducer(env, surfacetexture);
-    return ast;
+    auto consumer = SurfaceTexture_getSurfaceTexture(env, surfacetexture);
+    auto producer = SurfaceTexture_getProducer(env, surfacetexture);
+    return ASurfaceTexture_create(consumer, producer);
 }
 
 ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) {
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
index c35303e..2bd5fe2 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIFactory.java
@@ -19,36 +19,16 @@
 import android.content.Context;
 
 import com.android.systemui.dagger.SystemUIRootComponent;
-import com.android.systemui.navigationbar.car.CarFacetButtonController;
-
-import javax.inject.Singleton;
-
-import dagger.Component;
 
 /**
  * Class factory to provide car specific SystemUI components.
  */
 public class CarSystemUIFactory extends SystemUIFactory {
 
-    private CarDependencyComponent mCarDependencyComponent;
-
     @Override
     protected SystemUIRootComponent buildSystemUIRootComponent(Context context) {
-        mCarDependencyComponent = DaggerCarSystemUIFactory_CarDependencyComponent.builder()
-                .contextHolder(new ContextHolder(context))
-                .build();
         return DaggerCarSystemUIRootComponent.builder()
                 .contextHolder(new ContextHolder(context))
                 .build();
     }
-
-    public CarDependencyComponent getCarDependencyComponent() {
-        return mCarDependencyComponent;
-    }
-
-    @Singleton
-    @Component(modules = ContextHolder.class)
-    public interface CarDependencyComponent {
-        CarFacetButtonController getCarFacetButtonController();
-    }
 }
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 3b63e79..bffc6b9 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -26,6 +26,7 @@
 import com.android.systemui.dagger.SystemUIRootComponent;
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.recents.Recents;
@@ -38,18 +39,23 @@
 import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.volume.CarVolumeDialogComponent;
 import com.android.systemui.volume.VolumeDialogComponent;
 
+import java.util.Optional;
+
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 import dagger.Binds;
+import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -76,12 +82,23 @@
 
     @Singleton
     @Provides
-    static Divider provideDivider(Context context) {
-        return new Divider(context);
+    static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy) {
+        return new Divider(context, recentsOptionalLazy);
     }
 
     @Singleton
     @Provides
+    static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context,
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController bypassController) {
+        return new HeadsUpManagerPhone(context, statusBarStateController, bypassController);
+    }
+
+    @Binds
+    abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
+
+    @Singleton
+    @Provides
     @Named(LEAK_REPORT_EMAIL_NAME)
     static String provideLeakReportEmail() {
         return "buganizer-system+181579@google.com";
@@ -98,14 +115,11 @@
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
-    abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment(
+    abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
             KeyguardEnvironmentImpl keyguardEnvironment);
 
-    @Singleton
-    @Provides
-    static ShadeController provideShadeController(Context context) {
-        return SysUiServiceProvider.getComponent(context, StatusBar.class);
-    }
+    @Binds
+    abstract ShadeController provideShadeController(CarStatusBar statusBar);
 
     @Provides
     @Singleton
diff --git a/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
new file mode 100644
index 0000000..f90947c
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+  "auto-postsubmit": [
+    {
+      "name": "AndroidAutoUiTests",
+      "options" : [
+        {
+          "include-filter": "android.test.functional.auto.apps.HomeHelperTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
index 53a88a9..ed945e7 100644
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
@@ -19,8 +19,9 @@
 import android.service.notification.StatusBarNotification;
 
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -35,8 +36,12 @@
 public class CarNotificationEntryManager extends NotificationEntryManager {
 
     @Inject
-    public CarNotificationEntryManager(NotificationData notificationData, NotifLog notifLog) {
-        super(notificationData, notifLog);
+    public CarNotificationEntryManager(
+            NotifLog notifLog,
+            NotificationGroupManager groupManager,
+            NotificationRankingManager rankingManager,
+            KeyguardEnvironment keyguardEnvironment) {
+        super(notifLog, groupManager, rankingManager, keyguardEnvironment);
     }
 
     @Override
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..80ee371
--- /dev/null
+++ b/packages/CarSystemUI/src/com/android/systemui/car/CarServiceProvider.java
@@ -0,0 +1,79 @@
+/*
+ * 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 androidx.annotation.VisibleForTesting;
+
+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);
+                            }
+                        }
+                    }
+                });
+    }
+
+    @VisibleForTesting
+    public CarServiceProvider(Context context, Car car) {
+        mContext = context;
+        mCar = car;
+    }
+
+    /**
+     * 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/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
index c46e6e7..0b89992 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButton.java
@@ -29,9 +29,7 @@
 import android.widget.LinearLayout;
 
 import com.android.keyguard.AlphaOptimizedImageButton;
-import com.android.systemui.CarSystemUIFactory;
 import com.android.systemui.R;
-import com.android.systemui.SystemUIFactory;
 
 /**
  * CarFacetButton is a ui component designed to be used as a shortcut for an app of a defined
@@ -82,10 +80,6 @@
         TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CarFacetButton);
         setupIntents(typedArray);
         setupIcons(typedArray);
-        CarSystemUIFactory factory = SystemUIFactory.getInstance();
-        CarFacetButtonController carFacetButtonController = factory.getCarDependencyComponent()
-                .getCarFacetButtonController();
-        carFacetButtonController.addFacetButton(this);
     }
 
     /**
diff --git a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
index 30f63f0..f66e828 100644
--- a/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
+++ b/packages/CarSystemUI/src/com/android/systemui/navigationbar/car/CarFacetButtonController.java
@@ -43,6 +43,8 @@
 @Singleton
 public class CarFacetButtonController {
 
+    private final Set<CarFacetButton> mRegisteredViews = new HashSet<>();
+
     protected ButtonMap mButtonsByCategory = new ButtonMap();
     protected ButtonMap mButtonsByPackage = new ButtonMap();
     protected ButtonMap mButtonsByComponentName = new ButtonMap();
@@ -60,7 +62,11 @@
      * to get a reference to this controller via {@link com.android.systemui.Dependency}
      * and self add.
      */
-    public void addFacetButton(CarFacetButton facetButton) {
+    private void addFacetButton(CarFacetButton facetButton) {
+        if (mRegisteredViews.contains(facetButton)) {
+            return;
+        }
+
         String[] categories = facetButton.getCategories();
         for (int i = 0; i < categories.length; i++) {
             mButtonsByCategory.add(categories[i], facetButton);
@@ -74,6 +80,8 @@
         for (int i = 0; i < componentNames.length; i++) {
             mButtonsByComponentName.add(componentNames[i], facetButton);
         }
+
+        mRegisteredViews.add(facetButton);
     }
 
     /** Removes all buttons from the button maps. */
@@ -82,6 +90,7 @@
         mButtonsByPackage.clear();
         mButtonsByComponentName.clear();
         mSelectedFacetButtons.clear();
+        mRegisteredViews.clear();
     }
 
     /**
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 76%
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..fd9c488 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,42 +14,45 @@
  * 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;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 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 final Set<TemperatureView> mRegisteredViews = new HashSet<>();
+
     private CarHvacManager mHvacManager;
     private HashMap<HvacKey, List<TemperatureView>> mTempComponents = new HashMap<>();
 
@@ -85,22 +88,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,15 +109,16 @@
      * ({@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);
     }
 
     /**
      * Add component to list and initialize it if the connection is up.
      */
-    public void addHvacTextView(TemperatureView temperatureView) {
+    private void addHvacTextView(TemperatureView temperatureView) {
+        if (mRegisteredViews.contains(temperatureView)) {
+            return;
+        }
 
         HvacKey hvacKey = new HvacKey(temperatureView.getPropertyId(), temperatureView.getAreaId());
         if (!mTempComponents.containsKey(hvacKey)) {
@@ -124,6 +126,8 @@
         }
         mTempComponents.get(hvacKey).add(temperatureView);
         initComponent(temperatureView);
+
+        mRegisteredViews.add(temperatureView);
     }
 
     private void initComponents() {
@@ -169,6 +173,22 @@
      */
     public void removeAllComponents() {
         mTempComponents.clear();
+        mRegisteredViews.clear();
+    }
+
+    /**
+     * 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));
+            }
+        }
     }
 
     /**
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 1d14c34..4e5a3a6 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,12 +72,12 @@
 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;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -97,12 +96,12 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -132,6 +131,7 @@
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -161,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;
@@ -283,7 +283,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AssistManager assistManager,
+            Lazy<AssistManager> assistManagerLazy,
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
@@ -294,8 +294,11 @@
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
+            ScreenPinningRequest screenPinningRequest,
             DozeScrimController dozeScrimController,
+            VolumeComponent volumeComponent,
             CommandQueue commandQueue,
+            Optional<Recents> recents,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -305,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,
@@ -352,7 +359,7 @@
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
-                assistManager,
+                assistManagerLazy,
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
@@ -364,8 +371,11 @@
                 biometricUnlockControllerLazy,
                 dozeServiceHost,
                 powerManager,
+                screenPinningRequest,
                 dozeScrimController,
+                volumeComponent,
                 commandQueue,
+                recents,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
@@ -375,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);
@@ -422,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.
@@ -481,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);
 
@@ -553,7 +530,7 @@
                 new HandleBarCloseNotificationGestureListener());
 
         mTopNavBarNotificationTouchListener = (v, event) -> {
-            if (!mDeviceIsSetUpForUser) {
+            if (!mDeviceProvisionedController.isCurrentUserSetup()) {
                 return true;
             }
             boolean consumed = openGestureDetector.onTouchEvent(event);
@@ -583,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(
@@ -605,7 +575,7 @@
                         boolean hasUnseen =
                                 mNotificationDataManager.getUnseenNotificationCount() > 0;
                         mCarNavigationBarController.toggleAllNotificationsUnseenIndicator(
-                                mDeviceIsSetUpForUser, hasUnseen);
+                                mDeviceProvisionedController.isCurrentUserSetup(), hasUnseen);
                     }
                 });
 
@@ -859,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);
@@ -880,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
@@ -899,8 +861,6 @@
                     + "," + mStackScroller.getScrollY());
         }
 
-        pw.print("  mCarFacetButtonController=");
-        pw.println(mCarFacetButtonController);
         pw.print("  mFullscreenUserSwitcher=");
         pw.println(mFullscreenUserSwitcher);
         pw.print("  mCarBatteryController=");
@@ -965,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();
         }
@@ -1049,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 542fa44..4813d6d 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;
@@ -36,6 +37,8 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.navigationbar.car.CarNavigationBarController;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -53,12 +56,12 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -86,6 +89,7 @@
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.Optional;
 
@@ -152,7 +156,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AssistManager assistManager,
+            Lazy<AssistManager> assistManagerLazy,
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
@@ -163,8 +167,11 @@
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
+            ScreenPinningRequest screenPinningRequest,
             DozeScrimController dozeScrimController,
+            VolumeComponent volumeComponent,
             CommandQueue commandQueue,
+            Optional<Recents> recentsOptional,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -173,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,
@@ -220,7 +231,7 @@
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
-                assistManager,
+                assistManagerLazy,
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
@@ -231,8 +242,11 @@
                 biometricUnlockControllerLazy,
                 dozeServiceHost,
                 powerManager,
+                screenPinningRequest,
                 dozeScrimController,
+                volumeComponent,
                 commandQueue,
+                recentsOptional,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
@@ -241,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 4d6af95..5a34436 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogComponent.java
@@ -18,7 +18,7 @@
 
 import android.content.Context;
 
-import com.android.systemui.SystemUI;
+import com.android.systemui.car.CarServiceProvider;
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.plugins.VolumeDialog;
 
@@ -31,12 +31,20 @@
 @Singleton
 public class CarVolumeDialogComponent extends VolumeDialogComponent {
 
+    private CarVolumeDialogImpl mCarVolumeDialog;
+
     @Inject
-    public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator) {
-        super(context, keyguardViewMediator);
+    public CarVolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
+            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/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java
new file mode 100644
index 0000000..a71d1db
--- /dev/null
+++ b/packages/CarSystemUI/tests/src/com/android/systemui/navigationbar/car/hvac/HvacControllerTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.navigationbar.car.hvac;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.car.Car;
+import android.car.hardware.hvac.CarHvacManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.car.CarServiceProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+@SmallTest
+public class HvacControllerTest extends SysuiTestCase {
+
+    private static final int PROPERTY_ID = 1;
+    private static final int AREA_ID = 1;
+    private static final float VALUE = 72.0f;
+
+    private HvacController mHvacController;
+    private CarServiceProvider mCarServiceProvider;
+
+    @Mock
+    private Car mCar;
+    @Mock
+    private CarHvacManager mCarHvacManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mCar.isConnected()).thenReturn(true);
+        when(mCar.getCarManager(Car.HVAC_SERVICE)).thenReturn(mCarHvacManager);
+
+        mCarServiceProvider = new CarServiceProvider(mContext, mCar);
+        mHvacController = new HvacController(mCarServiceProvider);
+        mHvacController.connectToCarService();
+    }
+
+    @Test
+    public void connectToCarService_registersCallback() {
+        verify(mCarHvacManager).registerCallback(any());
+    }
+
+    @Test
+    public void addTemperatureViewToController_usingTemperatureView_registersView() {
+        TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+        mHvacController.addTemperatureViewToController(v);
+
+        verify(v).setTemp(VALUE);
+    }
+
+    @Test
+    public void addTemperatureViewToController_usingSameTemperatureView_registersFirstView() {
+        TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+        mHvacController.addTemperatureViewToController(v);
+        verify(v).setTemp(VALUE);
+        resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+
+        mHvacController.addTemperatureViewToController(v);
+        verify(v, never()).setTemp(VALUE);
+    }
+
+    @Test
+    public void addTemperatureViewToController_usingDifferentTemperatureView_registersBothViews() {
+        TemperatureTextView v1 = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+        mHvacController.addTemperatureViewToController(v1);
+        verify(v1).setTemp(VALUE);
+
+        TemperatureTextView v2 = setupMockTemperatureTextView(
+                PROPERTY_ID + 1,
+                AREA_ID + 1,
+                VALUE + 1);
+        mHvacController.addTemperatureViewToController(v2);
+        verify(v2).setTemp(VALUE + 1);
+    }
+
+    @Test
+    public void removeAllComponents_ableToRegisterSameView() {
+        TemperatureTextView v = setupMockTemperatureTextView(PROPERTY_ID, AREA_ID, VALUE);
+        mHvacController.addTemperatureViewToController(v);
+        verify(v).setTemp(VALUE);
+
+        mHvacController.removeAllComponents();
+        resetTemperatureView(v, PROPERTY_ID, AREA_ID);
+
+        mHvacController.addTemperatureViewToController(v);
+        verify(v).setTemp(VALUE);
+    }
+
+    private TemperatureTextView setupMockTemperatureTextView(int propertyId, int areaId,
+            float value) {
+        TemperatureTextView v = mock(TemperatureTextView.class);
+        resetTemperatureView(v, propertyId, areaId);
+        when(mCarHvacManager.isPropertyAvailable(propertyId, areaId)).thenReturn(true);
+        when(mCarHvacManager.getFloatProperty(propertyId, areaId)).thenReturn(value);
+        return v;
+    }
+
+    private void resetTemperatureView(TemperatureTextView view, int propertyId, int areaId) {
+        reset(view);
+        when(view.getPropertyId()).thenReturn(propertyId);
+        when(view.getAreaId()).thenReturn(areaId);
+    }
+}
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 738c425..19ae970 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -102,9 +102,10 @@
             Thread thread =
                     new Thread(
                             () -> {
-                                mDynSystem.startInstallation("userdata", mUserdataSize, false);
+                                mDynSystem.startInstallation();
+                                mDynSystem.createPartition("userdata", mUserdataSize, false);
                                 mInstallationSession =
-                                        mDynSystem.startInstallation("system", mSystemSize, true);
+                                        mDynSystem.createPartition("system", mSystemSize, true);
                             });
 
             thread.start();
@@ -157,6 +158,7 @@
                     reportedInstalledSize = installedSize;
                 }
             }
+            mDynSystem.finishInstallation();
             return null;
 
         } catch (Exception e) {
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/PackageInstaller/res/values-mr/strings.xml b/packages/PackageInstaller/res/values-mr/strings.xml
index 56661e8..da1c7a7 100644
--- a/packages/PackageInstaller/res/values-mr/strings.xml
+++ b/packages/PackageInstaller/res/values-mr/strings.xml
@@ -23,9 +23,9 @@
     <string name="installing" msgid="4921993079741206516">"इंस्‍टॉल होत आहे…"</string>
     <string name="installing_app" msgid="1165095864863849422">"<xliff:g id="PACKAGE_LABEL">%1$s</xliff:g> इंस्टॉल होत आहे…"</string>
     <string name="install_done" msgid="5987363587661783896">"अ‍ॅप इंस्टॉल झाले."</string>
-    <string name="install_confirm_question" msgid="8176284075816604590">"तुम्हाला हे अॅप्लिकेशन इंस्टॉल करायचे आहे का?"</string>
-    <string name="install_confirm_question_update" msgid="7942235418781274635">"तुम्हाच्या विद्यमान अॅप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string>
-    <string name="install_confirm_question_update_system" msgid="4713001702777910263">"तुम्हाला या बिल्ट-इन अॅप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string>
+    <string name="install_confirm_question" msgid="8176284075816604590">"तुम्हाला हे ॲप्लिकेशन इंस्टॉल करायचे आहे का?"</string>
+    <string name="install_confirm_question_update" msgid="7942235418781274635">"तुम्हाच्या विद्यमान ॲप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string>
+    <string name="install_confirm_question_update_system" msgid="4713001702777910263">"तुम्हाला या बिल्ट-इन ॲप्लिकेशनवर अपडेट इंस्टॉल करायचे आहे का? तुमचा विद्यमान डेटा गमावणार नाही."</string>
     <string name="install_failed" msgid="5777824004474125469">"अ‍ॅप इंस्टॉल झाले नाही."</string>
     <string name="install_failed_blocked" msgid="8512284352994752094">"पॅकेज इंस्टॉल होण्यापासून ब्लॉक केले होते."</string>
     <string name="install_failed_conflict" msgid="3493184212162521426">"पॅकेजचा विद्यमान पॅकेजशी विरोध असल्याने अ‍ॅप इंस्टॉल झाले नाही."</string>
@@ -52,7 +52,7 @@
     <string name="generic_error_dlg_text" msgid="5287861443265795232">"अ‍ॅप अनइंस्टॉल करणे शक्य झाले नाही."</string>
     <string name="uninstall_application_title" msgid="4045420072401428123">"अ‍ॅप अनइंस्टॉल करा"</string>
     <string name="uninstall_update_title" msgid="824411791011583031">"अपडेट अनइंस्टॉल करा"</string>
-    <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> खालील अॅपचा भाग आहे:"</string>
+    <string name="uninstall_activity_text" msgid="1928194674397770771">"<xliff:g id="ACTIVITY_NAME">%1$s</xliff:g> खालील ॲपचा भाग आहे:"</string>
     <string name="uninstall_application_text" msgid="3816830743706143980">"तुम्हाला हे अ‍ॅप अनइंस्टॉल करायचे आहे का?"</string>
     <string name="uninstall_application_text_all_users" msgid="575491774380227119">"तुम्हाला हे अ‍ॅप "<b>"सर्व"</b>" वापरकर्त्यांसाठी अनइंस्टॉल करायचे आहे का? अ‍ॅप्लिकेशन आणि त्याचा डेटा डिव्हाइसवरील "<b>"सर्व"</b>" वापरकर्त्यांकडून काढला जाईल."</string>
     <string name="uninstall_application_text_user" msgid="498072714173920526">"तुम्हाला <xliff:g id="USERNAME">%1$s</xliff:g> वापरकर्त्यासाठी हे अ‍ॅप अनइंस्टॉल करायचे आहे का?"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index d15a09f..ba9beb6 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -61,8 +61,7 @@
     <string name="speed_label_medium" msgid="9078405312828606976">"Medium"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Fast"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Very fast"</string>
-    <!-- no translation found for wifi_passpoint_expired (6540867261754427561) -->
-    <skip />
+    <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Expired"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnecting…"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index d15a09f..ba9beb6 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -61,8 +61,7 @@
     <string name="speed_label_medium" msgid="9078405312828606976">"Medium"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Fast"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Very fast"</string>
-    <!-- no translation found for wifi_passpoint_expired (6540867261754427561) -->
-    <skip />
+    <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Expired"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnecting…"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index d15a09f..ba9beb6 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -61,8 +61,7 @@
     <string name="speed_label_medium" msgid="9078405312828606976">"Medium"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Fast"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Very fast"</string>
-    <!-- no translation found for wifi_passpoint_expired (6540867261754427561) -->
-    <skip />
+    <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Expired"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnecting…"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index d15a09f..ba9beb6 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -61,8 +61,7 @@
     <string name="speed_label_medium" msgid="9078405312828606976">"Medium"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Fast"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Very fast"</string>
-    <!-- no translation found for wifi_passpoint_expired (6540867261754427561) -->
-    <skip />
+    <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Expired"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Disconnected"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Disconnecting…"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index 0e81ece..9648139 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -272,7 +272,7 @@
     <string name="dev_settings_warning_title" msgid="8251234890169074553">"Baimendu garapenerako ezarpenak?"</string>
     <string name="dev_settings_warning_message" msgid="37741686486073668">"Ezarpen hauek garapen-xedeetarako pentsatu dira soilik. Baliteke ezarpenen eraginez gailua matxuratzea edo funtzionamendu okerra izatea."</string>
     <string name="verify_apps_over_usb_title" msgid="6031809675604442636">"Egiaztatu USBko aplikazioak"</string>
-    <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak antzemateko"</string>
+    <string name="verify_apps_over_usb_summary" msgid="1317933737581167839">"Egiaztatu ADB/ADT bidez instalatutako aplikazioak portaera kaltegarriak atzemateko"</string>
     <string name="bluetooth_show_devices_without_names_summary" msgid="780964354377854507">"Bluetooth gailuak izenik gabe (MAC helbideak soilik) erakutsiko dira"</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="2006309932135547681">"Bluetooth bidezko bolumen absolutuaren eginbidea desgaitu egiten du urruneko gailuetan arazoak hautematen badira; esaterako, bolumena ozenegia bada edo ezin bada kontrolatu"</string>
     <string name="enable_terminal_title" msgid="3834790541986303654">"Tokiko terminala"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 70cfbc6..aa4ec76 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -61,8 +61,7 @@
     <string name="speed_label_medium" msgid="9078405312828606976">"Дунд"</string>
     <string name="speed_label_fast" msgid="2677719134596044051">"Хурдан"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Маш хурдан"</string>
-    <!-- no translation found for wifi_passpoint_expired (6540867261754427561) -->
-    <skip />
+    <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Хугацаа дууссан"</string>
     <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Салгагдсан"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Салгаж байна…"</string>
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/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
index e824508..5b9281cb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java
@@ -30,10 +30,12 @@
 public class EventLogWriter implements LogWriter {
 
     @Override
-    public void visible(Context context, int source, int category) {
+    public void visible(Context context, int source, int category, int latency) {
         final LogMaker logMaker = new LogMaker(category)
                 .setType(MetricsProto.MetricsEvent.TYPE_OPEN)
-                .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source);
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source)
+                .addTaggedData(MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE,
+                        latency);
         MetricsLogger.action(logMaker);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
index f187688..9d9c17f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/LogWriter.java
@@ -26,7 +26,7 @@
     /**
      * Logs a visibility event when view becomes visible.
      */
-    void visible(Context context, int source, int category);
+    void visible(Context context, int source, int category, int latency);
 
     /**
      * Logs a visibility event when view becomes hidden.
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
index 8cc3b5a..5cf44e1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/MetricsFeatureProvider.java
@@ -67,9 +67,16 @@
                 SettingsEnums.PAGE_UNKNOWN);
     }
 
-    public void visible(Context context, int source, int category) {
+    /**
+     * Logs an event when target page is visible.
+     *
+     * @param source from this page id to target page
+     * @param category the target page id
+     * @param latency the latency of target page creation
+     */
+    public void visible(Context context, int source, int category, int latency) {
         for (LogWriter writer : mLoggerWriters) {
-            writer.visible(context, source, category);
+            writer.visible(context, source, category, latency);
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
index 8090169..1c62879 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java
@@ -23,15 +23,16 @@
 import android.os.SystemClock;
 
 import androidx.lifecycle.Lifecycle.Event;
-import androidx.lifecycle.LifecycleObserver;
 import androidx.lifecycle.OnLifecycleEvent;
 
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnAttach;
 
 /**
  * Logs visibility change of a fragment.
  */
-public class VisibilityLoggerMixin implements LifecycleObserver {
+public class VisibilityLoggerMixin implements LifecycleObserver, OnAttach {
 
     private static final String TAG = "VisibilityLoggerMixin";
 
@@ -39,24 +40,36 @@
 
     private MetricsFeatureProvider mMetricsFeature;
     private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN;
-    private long mVisibleTimestamp;
+    private long mTimestamp;
 
     public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) {
         mMetricsCategory = metricsCategory;
         mMetricsFeature = metricsFeature;
     }
 
+    @Override
+    public void onAttach() {
+        mTimestamp = SystemClock.elapsedRealtime();
+    }
+
     @OnLifecycleEvent(Event.ON_RESUME)
     public void onResume() {
-        mVisibleTimestamp = SystemClock.elapsedRealtime();
-        if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
-            mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory);
+        if (mMetricsFeature == null || mMetricsCategory == METRICS_CATEGORY_UNKNOWN) {
+            return;
+        }
+        if (mTimestamp != 0L) {
+            final int elapse = (int) (SystemClock.elapsedRealtime() - mTimestamp);
+            mMetricsFeature.visible(null /* context */, mSourceMetricsCategory,
+                    mMetricsCategory, elapse);
+        } else {
+            mMetricsFeature.visible(null /* context */, mSourceMetricsCategory,
+                    mMetricsCategory, 0);
         }
     }
 
     @OnLifecycleEvent(Event.ON_PAUSE)
     public void onPause() {
-        mVisibleTimestamp = 0;
+        mTimestamp = 0;
         if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) {
             mMetricsFeature.hidden(null /* context */, mMetricsCategory);
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
index 56de280..f87c886 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java
@@ -94,11 +94,14 @@
         }
     }
 
+    /**
+     * Pass all onAttach event to {@link LifecycleObserver}.
+     */
     public void onAttach(Context context) {
         for (int i = 0, size = mObservers.size(); i < size; i++) {
             final LifecycleObserver observer = mObservers.get(i);
             if (observer instanceof OnAttach) {
-                ((OnAttach) observer).onAttach(context);
+                ((OnAttach) observer).onAttach();
             }
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
index e28c387..1e7d01c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnAttach.java
@@ -15,12 +15,12 @@
  */
 package com.android.settingslib.core.lifecycle.events;
 
-import android.content.Context;
-
 /**
- * @deprecated pass {@link Context} in constructor instead
+ * An Interface used by {@link LifecycleObserver} which changes to onAttach state.
  */
-@Deprecated
 public interface OnAttach {
-    void onAttach(Context context);
+    /**
+     * Called when {@link LifecycleObserver} is entering onAttach
+     */
+    void onAttach();
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
index d5d2e9e..f506b7c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/OWNERS
@@ -1,7 +1,7 @@
 # Default reviewers for this and subdirectories.
+qal@google.com
+arcwang@google.com
+govenliu@google.com
 asapperstein@google.com
-asargent@google.com
-dling@google.com
-zhfan@google.com
 
 # Emergency approvers in case the above are not available
\ No newline at end of file
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/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
index 097db17..f070a37 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java
@@ -65,7 +65,7 @@
 
         verify(mMetricsFeature, times(1))
                 .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN),
-                        eq(TestInstrumentable.TEST_METRIC));
+                        eq(TestInstrumentable.TEST_METRIC), anyInt());
     }
 
     @Test
@@ -80,7 +80,7 @@
 
         verify(mMetricsFeature, times(1))
                 .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES),
-                        eq(TestInstrumentable.TEST_METRIC));
+                        eq(TestInstrumentable.TEST_METRIC), anyInt());
     }
 
     @Test
@@ -118,7 +118,8 @@
         TestActivity testActivity = ac.get();
         MockitoAnnotations.initMocks(testActivity);
         ac.create().start().resume();
-        verify(testActivity.mMetricsFeatureProvider, times(1)).visible(any(), anyInt(), anyInt());
+        verify(testActivity.mMetricsFeatureProvider, times(1)).visible(any(), anyInt(), anyInt(),
+                anyInt());
         ac.pause().stop().destroy();
         verify(testActivity.mMetricsFeatureProvider, times(1)).hidden(any(), anyInt());
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
index 29e37e4..97e6d50 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java
@@ -19,7 +19,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import android.content.Context;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -96,7 +95,6 @@
             OnOptionsItemSelected {
 
         boolean mOnAttachObserved;
-        boolean mOnAttachHasContext;
         boolean mOnStartObserved;
         boolean mOnResumeObserved;
         boolean mOnPauseObserved;
@@ -107,9 +105,8 @@
         boolean mOnOptionsItemSelectedObserved;
 
         @Override
-        public void onAttach(Context context) {
+        public void onAttach() {
             mOnAttachObserved = true;
-            mOnAttachHasContext = context != null;
         }
 
         @Override
@@ -194,7 +191,6 @@
         assertThat(fragment.mFragObserver.mOnOptionsItemSelectedObserved).isTrue();
 
         assertThat(fragment.mFragObserver.mOnAttachObserved).isTrue();
-        assertThat(fragment.mFragObserver.mOnAttachHasContext).isTrue();
         assertThat(fragment.mFragObserver.mOnStartObserved).isTrue();
         assertThat(fragment.mFragObserver.mOnResumeObserved).isTrue();
         fragment.onPause();
@@ -218,7 +214,6 @@
         assertThat(fragment.mFragObserver.mOnOptionsItemSelectedObserved).isTrue();
 
         assertThat(fragment.mFragObserver.mOnAttachObserved).isTrue();
-        assertThat(fragment.mFragObserver.mOnAttachHasContext).isTrue();
         assertThat(fragment.mFragObserver.mOnStartObserved).isTrue();
         assertThat(fragment.mFragObserver.mOnResumeObserved).isTrue();
         fragment.onPause();
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 44de09b..386626d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -41,6 +41,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
+import android.sysprop.TelephonyProperties;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -2487,9 +2488,7 @@
 
             // Data roaming default, based on build
             loadSetting(stmt, Settings.Global.DATA_ROAMING,
-                    "true".equalsIgnoreCase(
-                            SystemProperties.get("ro.com.android.dataroaming",
-                                    "false")) ? 1 : 0);
+                    TelephonyProperties.data_roaming().orElse(false) ? 1 : 0);
 
             loadBooleanSetting(stmt, Settings.Global.DEVICE_PROVISIONED,
                     R.bool.def_device_provisioned);
@@ -2510,9 +2509,7 @@
 
             // Mobile Data default, based on build
             loadSetting(stmt, Settings.Global.MOBILE_DATA,
-                    "true".equalsIgnoreCase(
-                            SystemProperties.get("ro.com.android.mobiledata",
-                                    "true")) ? 1 : 0);
+                    TelephonyProperties.mobile_data().orElse(true) ? 1 : 0);
 
             loadBooleanSetting(stmt, Settings.Global.NETSTATS_ENABLED,
                     R.bool.def_netstats_enabled);
@@ -2564,20 +2561,17 @@
 
             // Set the preferred network mode to target desired value or Default
             // value defined in system property
-            String val = "";
-            String mode;
+            StringBuilder val = new StringBuilder();
+            List<Integer> defaultNetworks = TelephonyProperties.default_network();
             for (int phoneId = 0;
                     phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) {
-                mode = TelephonyManager.getTelephonyProperty(phoneId,
-                        "ro.telephony.default_network",
-                        Integer.toString(RILConstants.PREFERRED_NETWORK_MODE));
-                if (phoneId == 0) {
-                    val = mode;
-                } else {
-                    val = val + "," + mode;
-                }
+                int mode = defaultNetworks.size() <= phoneId
+                        || defaultNetworks.get(phoneId) == null
+                        ? RILConstants.PREFERRED_NETWORK_MODE : defaultNetworks.get(phoneId);
+                if (phoneId > 0) val.append(',');
+                val.append(mode);
             }
-            loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val);
+            loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val.toString());
 
             // Set the preferred cdma subscription source to target desired value or default
             // value defined in Phone
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 7765935..f5d1ccf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -154,7 +154,6 @@
     private static final String TABLE_SYSTEM = "system";
     private static final String TABLE_SECURE = "secure";
     private static final String TABLE_GLOBAL = "global";
-    private static final String TABLE_CONFIG = "config";
 
     // Old tables no longer exist.
     private static final String TABLE_FAVORITES = "favorites";
diff --git a/packages/Shell/res/values-hu/strings.xml b/packages/Shell/res/values-hu/strings.xml
index 90966fc..441446cf 100644
--- a/packages/Shell/res/values-hu/strings.xml
+++ b/packages/Shell/res/values-hu/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="3701846017049540910">"Héj"</string>
+    <string name="app_label" msgid="3701846017049540910">"Parancsértelmező"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Hibajelentések"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) létrehozása folyamatban"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) rögzítve"</string>
diff --git a/packages/Shell/res/values-kk/strings.xml b/packages/Shell/res/values-kk/strings.xml
index 6ee1cc5..82c02a1 100644
--- a/packages/Shell/res/values-kk/strings.xml
+++ b/packages/Shell/res/values-kk/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="3701846017049540910">"Қабыршық"</string>
+    <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Қате туралы есептер"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жасалуда"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі жазып алынды"</string>
diff --git a/packages/Shell/res/values-ky/strings.xml b/packages/Shell/res/values-ky/strings.xml
index 4941bab..2499aba 100644
--- a/packages/Shell/res/values-ky/strings.xml
+++ b/packages/Shell/res/values-ky/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="3701846017049540910">"Командалык кабык"</string>
+    <string name="app_label" msgid="3701846017049540910">"Кабык"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Мүчүлүштүк тууралуу кабар берүүлөр"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> түзүлүүдө"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Мүчүлүштүк тууралуу билдирүү <xliff:g id="ID">#%d</xliff:g> жаздырылды"</string>
diff --git a/packages/Shell/res/values-mk/strings.xml b/packages/Shell/res/values-mk/strings.xml
index 983e664..3d18d30 100644
--- a/packages/Shell/res/values-mk/strings.xml
+++ b/packages/Shell/res/values-mk/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="3701846017049540910">"Обвивка"</string>
+    <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Извештаи за грешки"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Се генерира извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Извештајот за грешки <xliff:g id="ID">#%d</xliff:g> е снимен"</string>
diff --git a/packages/SystemUI/README.md b/packages/SystemUI/README.md
index a4dbf38..f170a11 100644
--- a/packages/SystemUI/README.md
+++ b/packages/SystemUI/README.md
@@ -24,12 +24,6 @@
 ConfigurationController). They also receive a callback for onBootCompleted
 since these objects may be started before the device has finished booting.
 
-SystemUI and SystemUIApplication also have methods for putComponent and
-getComponent which were existing systems to get a hold of other parts of
-sysui before Dependency existed. Generally new things should not be added
-to putComponent, instead Dependency and other refactoring is preferred to
-make sysui structure cleaner.
-
 Each SystemUI service is expected to be a major part of system ui and the
 goal is to minimize communication between them. So in general they should be
 relatively silo'd.
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index e86fa10..1ea0bb7 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -153,5 +153,5 @@
     </plurals>
     <string name="clock_title_default" msgid="6645600990069154049">"डीफॉल्ट"</string>
     <string name="clock_title_bubble" msgid="1286365278681892114">"बबल"</string>
-    <string name="clock_title_analog" msgid="4047401488577315053">"अॅनालॉग"</string>
+    <string name="clock_title_analog" msgid="4047401488577315053">"ॲनालॉग"</string>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 82a4a19..21d68d5 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -102,10 +102,10 @@
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="8476407539834855">"तपाईंले <xliff:g id="NUMBER">%d</xliff:g> पटक गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नुभएको छ। कार्य प्रोफाइललाई यसका सबै डेटा मेटिने गरी हटाइने छ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="956706236554092172">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो ट्याब्लेट अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="8364140853305528449">"तपाईंले <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक आफ्नो अनलक गर्ने ढाँचा गलत रूपमा कोर्नुभयो। थप <xliff:g id="NUMBER_1">%2$d</xliff:g> असफल प्रयासहरूपछि, तपाईंलाई एउटा इमेल खाता प्रयोग गरेर आफ्नो फोन अनलक गर्न आग्रह गरिनेछ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा फेरि प्रयास गर्नुहोस्।"</string>
-    <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"SIM को PIN कोड गलत छ। तपाईंले अब अाफ्नो यन्त्र खोल्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नै पर्ने हुन्छ।"</string>
+    <string name="kg_password_wrong_pin_code_pukked" msgid="3389829202093674267">"SIM को PIN कोड गलत छ। तपाईंले अब आफ्नो यन्त्र खोल्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नै पर्ने हुन्छ।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="4314341367727055967">
       <item quantity="other">SIM को PIN कोड गलत छ, तपाईं अझै <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
-      <item quantity="one">SIM को PIN कोड गलत छ,तपाईंले अाफ्नो यन्त्र अनलक गर्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नैपर्ने अवस्था आउनु अघि तपाईं अझै <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
+      <item quantity="one">SIM को PIN कोड गलत छ,तपाईंले आफ्नो यन्त्र अनलक गर्न आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नैपर्ने अवस्था आउनु अघि तपाईं अझै <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास गर्न सक्नुहुन्छ।</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="3329017604125179374">"SIM काम नलाग्ने भएको छ। आफ्नो सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।"</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="2287504898931957513">
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-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index f97d1ec..ec90354 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"Інтэрфейс карыстальніка сістэмы"</string>
+    <string name="app_label" msgid="7164937344850004466">"Інтэрфейс сістэмы"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ачысціць"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Без апавяшчэнняў"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Пастаянныя"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b6730cf..841abde 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -277,10 +277,10 @@
     <string name="accessibility_quick_settings_sensor_privacy_changed_on" msgid="529705259565826355">"Aktibatu da sentsoreen pribatutasuna."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bistaratu distira"</string>
     <string name="accessibility_ambient_display_charging" msgid="9084521679384069087">"Kargatzen"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erabilera eten da"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erab. pausatu da"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera pausatu da"</string>
     <string name="data_usage_disabled_dialog_mobile_title" msgid="6801382439018099779">"Datu-konexioa pausatu egin da"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera pausatu da"</string>
     <string name="data_usage_disabled_dialog" msgid="4919541636934603816">"Iritsi zara ezarri zenuen datu-mugara. Datu-konexioa erabiltzeari utzi diozu.\n\nDatu-konexioa erabiltzeari berrekiten badiozu, datuen erabileragatiko gastuak izango dituzu."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS seinalearen bila"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 12e06fd0..90a6987 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"L\'interface"</string>
+    <string name="app_label" msgid="7164937344850004466">"Interface"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 85f8cf4..a029e19 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"IU sistema"</string>
+    <string name="app_label" msgid="7164937344850004466">"IU do sistema"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Non hai notificacións"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En curso"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index c32ec38..4c6edc1 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -851,9 +851,9 @@
     <string name="pip_pause" msgid="8881063404466476571">"रोकें"</string>
     <string name="pip_skip_to_next" msgid="1948440006726306284">"अगले पर जाएं"</string>
     <string name="pip_skip_to_prev" msgid="1955311326688637914">"पिछले पर जाएं"</string>
-    <string name="thermal_shutdown_title" msgid="4458304833443861111">"गर्म होने के कारण फ़ोन बंद हुआ"</string>
+    <string name="thermal_shutdown_title" msgid="4458304833443861111">"गर्म होने की वजह से फ़ोन बंद हुआ"</string>
     <string name="thermal_shutdown_message" msgid="9006456746902370523">"आपका फ़ोन अब सामान्य रूप से चल रहा है"</string>
-    <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"फ़ोन बहुत गर्म हो गया था, इसलिए वह ठंडा होने के लिए बंद हो गया. फ़ोन अब सामान्य रूप से चल रहा है.\n\nफ़ोन तब बहुत गर्म हो सकता है जब आप:\n	• ज़्यादा संसाधनों का उपयोग करने वाले ऐप चलाते हैं (जैसे गेमिंग, वीडियो या मार्गदर्शक ऐप)\n	• बड़ी फ़ाइलें डाउनलोड या अपलोड करते हैं\n	• उच्च तापमान में फ़ोन का उपयोग करते हैं"</string>
+    <string name="thermal_shutdown_dialog_message" msgid="566347880005304139">"फ़ोन बहुत गर्म हो गया था, इसलिए ठंडा होने के लिए बंद हो गया. फ़ोन अब अच्छे से चल रहा है.\n\nफ़ोन तब बहुत गर्म हो सकता है जब आप:\n	• ज़्यादा रिसॉर्स का इस्तेमाल करने वाले ऐप्लिकेशन चलाते हैं (जैसे गेमिंग, वीडियो या नेविगेशन ऐप्लिकेशन)\n	• बड़ी फ़ाइलें डाउनलोड या अपलोड करते हैं\n	• ज़्यादा तापमान में फ़ोन का इस्तेमाल करते हैं"</string>
     <string name="high_temp_title" msgid="4589508026407318374">"फ़ोन गर्म हो रहा है"</string>
     <string name="high_temp_notif_message" msgid="5642466103153429279">"फ़ोन के ठंडा होने के दौरान कुछ सुविधाएं सीमित होती हैं"</string>
     <string name="high_temp_dialog_message" msgid="6840700639374113553">"आपका फ़ोन अपने आप ठंडा होने की कोशिश करेगा. आप अब भी अपने फ़ोन का उपयोग कर सकते हैं, लेकिन हो सकता है कि यह धीमी गति से चले.\n\nठंडा हो जाने पर आपका फ़ोन सामान्य रूप से चलेगा."</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index cf9c4e0..b9eaddf 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"Sistem UI"</string>
+    <string name="app_label" msgid="7164937344850004466">"UI Sistem"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Bersihkan"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Tidak ada notifikasi"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Berkelanjutan"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5759e4b..351ace8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -135,7 +135,7 @@
     <string name="biometric_dialog_wrong_pattern" msgid="4808369401645512099">"パターンが正しくありません"</string>
     <string name="biometric_dialog_wrong_password" msgid="2343518162282889518">"パスワードが正しくありません"</string>
     <string name="biometric_dialog_credential_too_many_attempts" msgid="1556206869468265728">"間違えた回数が上限を超えました。\n<xliff:g id="NUMBER">%d</xliff:g> 秒後にもう一度お試しください。"</string>
-    <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"指紋認証センサーをタップしてください"</string>
+    <string name="fingerprint_dialog_touch_sensor" msgid="8511557690663181761">"指紋認証センサーをタップ"</string>
     <string name="accessibility_fingerprint_dialog_fingerprint_icon" msgid="3125122495414253226">"指紋アイコン"</string>
     <string name="face_dialog_looking_for_face" msgid="7049276266074494689">"顔を認証しています…"</string>
     <string name="accessibility_face_dialog_face_icon" msgid="2658119009870383490">"顔アイコン"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 4f87cf1..042ffd8 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"ចំណុច​ប្រទាក់​ប្រព័ន្ធ"</string>
+    <string name="app_label" msgid="7164937344850004466">"UI ប្រព័ន្ធ"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"សម្អាត"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"គ្មាន​ការ​ជូន​ដំណឹង"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"បន្ត"</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 7324c51..d6a54f8 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -520,8 +520,8 @@
     <string name="monitoring_description_ca_cert_settings_separator" msgid="4987350385906393626">" "</string>
     <string name="monitoring_description_ca_cert_settings" msgid="5489969458872997092">"विश्वासू क्रेडेंशियल उघडा"</string>
     <string name="monitoring_description_network_logging" msgid="7223505523384076027">"आपल्या प्रशासकाने नेटवर्क लॉगिंग चालू केले आहे, जे आपल्या डिव्हाइसवरील रहदारीचे निरीक्षण करते.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा."</string>
-    <string name="monitoring_description_vpn" msgid="4445150119515393526">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क अॅक्टिव्हिटीचे परीक्षण करू शकतो."</string>
-    <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क अॅक्टिव्हिटीचे निरीक्षण करू शकते."</string>
+    <string name="monitoring_description_vpn" msgid="4445150119515393526">"तुम्ही VPN कनेक्शन सेट करण्यासाठी अ‍ॅपला परवानगी दिली.\n\nहा अ‍ॅप ईमेल, अ‍ॅप्स आणि वेबसाइटसह, तुमच्या डिव्हाइस आणि नेटवर्क ॲक्टिव्हिटीचे परीक्षण करू शकतो."</string>
+    <string name="monitoring_description_vpn_profile_owned" msgid="2958019119161161530">"तुमचे कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते.\n\nतुमचा प्रशासक ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करण्यास सक्षम आहे.\n\nअधिक माहितीसाठी आपल्या प्रशासकाशी संपर्क साधा.\n\nतुम्ही VPN शी देखील कनेक्ट आहात, जे आपल्या नेटवर्क ॲक्टिव्हिटीचे निरीक्षण करू शकते."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="1828472472674709532">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तुम्ही <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
@@ -622,7 +622,7 @@
     <string name="tuner_toast" msgid="603429811084428439">"अभिनंदन! सिस्टम UI ट्युनर सेटिंग्जमध्‍ये जोडले गेले आहे"</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"सेटिंग्ज मधून काढा"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"सेटिंग्ज मधून सिस्टम UI ट्युनर काढून त्याची सर्व वैशिष्ट्‍ये वापरणे थांबवायचे?"</string>
-    <string name="activity_not_found" msgid="348423244327799974">"अॅप्लिकेशन आपल्या डिव्हाइसवर इंस्टॉल केलेला नाही"</string>
+    <string name="activity_not_found" msgid="348423244327799974">"ॲप्लिकेशन आपल्या डिव्हाइसवर इंस्टॉल केलेला नाही"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"घड्याळाचे सेकंद दर्शवा"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्याळाचे सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
@@ -735,7 +735,7 @@
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"सूचना"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"कीबोर्ड शॉर्टकट"</string>
     <string name="keyboard_shortcut_group_system_switch_input" msgid="8413348767825486492">"कीबोर्ड लेआउट स्विच करा"</string>
-    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"अॅप्लिकेशन"</string>
+    <string name="keyboard_shortcut_group_applications" msgid="9129465955073449206">"ॲप्लिकेशन"</string>
     <string name="keyboard_shortcut_group_applications_assist" msgid="9095441910537146013">"सहाय्य"</string>
     <string name="keyboard_shortcut_group_applications_browser" msgid="6465985474000766533">"ब्राउझर"</string>
     <string name="keyboard_shortcut_group_applications_contacts" msgid="2064197111278436375">"संपर्क"</string>
@@ -893,12 +893,12 @@
     <string name="bt_is_off" msgid="2640685272289706392">"ब्लूटूथ बंद आहे"</string>
     <string name="dnd_is_off" msgid="6167780215212497572">"व्यत्यय आणू नका बंद आहे"</string>
     <string name="qs_dnd_prompt_auto_rule" msgid="862559028345233052">"व्यत्यय आणू नका एका <xliff:g id="ID_1">%s</xliff:g> स्वयंचलित नियमाने चालू केले."</string>
-    <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"व्यत्यय आणू नका (<xliff:g id="ID_1">%s</xliff:g>) अॅपने चालू केले."</string>
-    <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"व्यत्यय आणू नका एका स्वयंचलित नियमाने किंवा अॅपने चालू केले."</string>
+    <string name="qs_dnd_prompt_app" msgid="7978037419334156034">"व्यत्यय आणू नका (<xliff:g id="ID_1">%s</xliff:g>) ॲपने चालू केले."</string>
+    <string name="qs_dnd_prompt_auto_rule_app" msgid="2599343675391111951">"व्यत्यय आणू नका एका स्वयंचलित नियमाने किंवा ॲपने चालू केले."</string>
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> पर्यंत"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ठेवा"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"पुनर्स्थित करा"</string>
-    <string name="running_foreground_services_title" msgid="381024150898615683">"अॅप्‍स बॅकग्राउंडमध्‍ये चालू आहेत"</string>
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ॲप्‍स बॅकग्राउंडमध्‍ये चालू आहेत"</string>
     <string name="running_foreground_services_msg" msgid="6326247670075574355">"बॅटरी आणि डेटा वापराच्‍या तपशीलांसाठी टॅप करा"</string>
     <string name="mobile_data_disable_title" msgid="1068272097382942231">"मोबाइल डेटा बंद करायचा?"</string>
     <string name="mobile_data_disable_message" msgid="4756541658791493506">"तुम्हाला <xliff:g id="CARRIER">%s</xliff:g> मधून डेटा किंवा इंटरनेटचा अ‍ॅक्सेस नसेल. इंटरनेट फक्त वाय-फाय मार्फत उपलब्ध असेल."</string>
@@ -919,7 +919,7 @@
     <string name="auto_saver_okay_action" msgid="2701221740227683650">"समजले"</string>
     <string name="heap_dump_tile_name" msgid="9141031328971226374">"SysUI हीप डंप करा"</string>
     <string name="ongoing_privacy_chip_content_single_app" msgid="4479560741898690064">"<xliff:g id="APP">%1$s</xliff:g> तुमचे <xliff:g id="TYPES_LIST">%2$s</xliff:g> वापरत आहे."</string>
-    <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8640691753867990511">"अॅप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string>
+    <string name="ongoing_privacy_chip_content_multiple_apps" msgid="8640691753867990511">"ॲप्लिकेशन्स तुमचे <xliff:g id="TYPES_LIST">%s</xliff:g> वापरत आहे."</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
     <string name="ongoing_privacy_dialog_last_separator" msgid="2400503446627122483">" आणि "</string>
     <string name="privacy_type_camera" msgid="1676604631892420333">"कॅमेरा"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index f7f4d81..b200ac6 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"Sist Arayüzü"</string>
+    <string name="app_label" msgid="7164937344850004466">"Sistem Arayüzü"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Temizle"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index f538853..8d3697e 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -19,7 +19,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="7164937344850004466">"UI tizimi"</string>
+    <string name="app_label" msgid="7164937344850004466">"Tizim interfeysi"</string>
     <string name="status_bar_clear_all_button" msgid="7774721344716731603">"Tozalash"</string>
     <string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirishnomalar yo‘q"</string>
     <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Hali bajarilmagan"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index e06380e..3138547 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/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 21b52c1..06aba40 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -38,7 +38,6 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
 
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settingslib.WirelessUtils;
 import com.android.systemui.Dependency;
@@ -106,7 +105,7 @@
             updateCarrierText();
         }
 
-        public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+        public void onSimStateChanged(int subId, int slotId, int simState) {
             if (slotId < 0 || slotId >= mSimSlotsNumber) {
                 Log.d(TAG, "onSimStateChanged() - slotId invalid: " + slotId
                         + " mTelephonyCapable: " + Boolean.toString(mTelephonyCapable));
@@ -191,7 +190,7 @@
             CharSequence[] carrierNames, int[] subOrderBySlot, boolean noSims) {
         final CharSequence carrier = "";
         CharSequence carrierTextForSimIOError = getCarrierTextForSimState(
-                IccCardConstants.State.CARD_IO_ERROR, carrier);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR, carrier);
         // mSimErrorState has the state of each sim indexed by slotID.
         for (int index = 0; index < getTelephonyManager().getActiveModemCount(); index++) {
             if (!mSimErrorState[index]) {
@@ -288,7 +287,7 @@
             carrierNames[i] = "";
             subsIds[i] = subId;
             subOrderBySlot[subs.get(i).getSimSlotIndex()] = i;
-            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+            int simState = mKeyguardUpdateMonitor.getSimState(subId);
             CharSequence carrierName = subs.get(i).getCarrierName();
             CharSequence carrierTextForSimState = getCarrierTextForSimState(simState, carrierName);
             if (DEBUG) {
@@ -298,7 +297,7 @@
                 allSimsMissing = false;
                 carrierNames[i] = carrierTextForSimState;
             }
-            if (simState == IccCardConstants.State.READY) {
+            if (simState == TelephonyManager.SIM_STATE_READY) {
                 ServiceState ss = mKeyguardUpdateMonitor.mServiceStates.get(subId);
                 if (ss != null && ss.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
                     // hack for WFC (IWLAN) not turning off immediately once
@@ -406,8 +405,7 @@
      *
      * @return Carrier text if not in missing state, null otherwise.
      */
-    private CharSequence getCarrierTextForSimState(IccCardConstants.State simState,
-            CharSequence text) {
+    private CharSequence getCarrierTextForSimState(int simState, CharSequence text) {
         CharSequence carrierText = null;
         CarrierTextController.StatusMode status = getStatusForIccState(simState);
         switch (status) {
@@ -498,37 +496,32 @@
     /**
      * Determine the current status of the lock screen given the SIM state and other stuff.
      */
-    private CarrierTextController.StatusMode getStatusForIccState(IccCardConstants.State simState) {
-        // Since reading the SIM may take a while, we assume it is present until told otherwise.
-        if (simState == null) {
-            return CarrierTextController.StatusMode.Normal;
-        }
-
+    private CarrierTextController.StatusMode getStatusForIccState(int simState) {
         final boolean missingAndNotProvisioned =
                 !Dependency.get(KeyguardUpdateMonitor.class).isDeviceProvisioned()
-                        && (simState == IccCardConstants.State.ABSENT
-                        || simState == IccCardConstants.State.PERM_DISABLED);
+                        && (simState == TelephonyManager.SIM_STATE_ABSENT
+                        || simState == TelephonyManager.SIM_STATE_PERM_DISABLED);
 
         // Assume we're NETWORK_LOCKED if not provisioned
-        simState = missingAndNotProvisioned ? IccCardConstants.State.NETWORK_LOCKED : simState;
+        simState = missingAndNotProvisioned ? TelephonyManager.SIM_STATE_NETWORK_LOCKED : simState;
         switch (simState) {
-            case ABSENT:
+            case TelephonyManager.SIM_STATE_ABSENT:
                 return CarrierTextController.StatusMode.SimMissing;
-            case NETWORK_LOCKED:
+            case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
                 return CarrierTextController.StatusMode.SimMissingLocked;
-            case NOT_READY:
+            case TelephonyManager.SIM_STATE_NOT_READY:
                 return CarrierTextController.StatusMode.SimNotReady;
-            case PIN_REQUIRED:
+            case TelephonyManager.SIM_STATE_PIN_REQUIRED:
                 return CarrierTextController.StatusMode.SimLocked;
-            case PUK_REQUIRED:
+            case TelephonyManager.SIM_STATE_PUK_REQUIRED:
                 return CarrierTextController.StatusMode.SimPukLocked;
-            case READY:
+            case TelephonyManager.SIM_STATE_READY:
                 return CarrierTextController.StatusMode.Normal;
-            case PERM_DISABLED:
+            case TelephonyManager.SIM_STATE_PERM_DISABLED:
                 return CarrierTextController.StatusMode.SimPermDisabled;
-            case UNKNOWN:
+            case TelephonyManager.SIM_STATE_UNKNOWN:
                 return CarrierTextController.StatusMode.SimUnknown;
-            case CARD_IO_ERROR:
+            case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
                 return CarrierTextController.StatusMode.SimIoError;
         }
         return CarrierTextController.StatusMode.SimUnknown;
@@ -575,7 +568,7 @@
         return list;
     }
 
-    private CharSequence getCarrierHelpTextForSimState(IccCardConstants.State simState,
+    private CharSequence getCarrierHelpTextForSimState(int simState,
             String plmn, String spn) {
         int carrierHelpTextId = 0;
         CarrierTextController.StatusMode status = getStatusForIccState(simState);
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index ecd8c8d..867014b6 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -37,7 +37,6 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
@@ -59,7 +58,7 @@
     KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
         @Override
-        public void onSimStateChanged(int subId, int slotId, State simState) {
+        public void onSimStateChanged(int subId, int slotId, int simState) {
             updateEmergencyCallButton();
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b9fe933..91b22d1 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -46,6 +46,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUIFactory;
@@ -617,6 +618,15 @@
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
                     StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
+                // Force a garbage collection in an attempt to erase any lockscreen password left in
+                // memory. Do it asynchronously with a 5-sec delay to avoid making the keyguard
+                // dismiss animation janky.
+                ThreadUtils.postOnBackgroundThread(() -> {
+                    try {
+                        Thread.sleep(5000);
+                    } catch (InterruptedException ignored) { }
+                    Runtime.getRuntime().gc();
+                });
             } else {
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
                     StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
index 64b4d32..17abfae 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityModel.java
@@ -20,8 +20,8 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.systemui.Dependency;
 
@@ -66,12 +66,12 @@
         KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
 
         if (mIsPukScreenAvailable && SubscriptionManager.isValidSubscriptionId(
-                monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED))) {
+                monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED))) {
             return SecurityMode.SimPuk;
         }
 
         if (SubscriptionManager.isValidSubscriptionId(
-                monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED))) {
+                monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED))) {
             return SecurityMode.SimPin;
         }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index b1502b9..b960de5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -38,8 +38,6 @@
 import android.widget.ImageView;
 
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -66,10 +64,10 @@
 
     KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
         @Override
-        public void onSimStateChanged(int subId, int slotId, State simState) {
+        public void onSimStateChanged(int subId, int slotId, int simState) {
             if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
             switch(simState) {
-                case READY: {
+                case TelephonyManager.SIM_STATE_READY: {
                     mRemainingAttempts = -1;
                     resetState();
                     break;
@@ -157,7 +155,7 @@
 
     private void handleSubInfoChangeIfNeeded() {
         KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
-        int subId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+        int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PIN_REQUIRED);
         if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
             mSubId = subId;
             mShowDefaultMessage = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 70237a0..7e08ab3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -37,8 +37,6 @@
 import android.widget.ImageView;
 
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -69,12 +67,12 @@
 
     KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
         @Override
-        public void onSimStateChanged(int subId, int slotId, State simState) {
+        public void onSimStateChanged(int subId, int slotId, int simState) {
             if (DEBUG) Log.v(TAG, "onSimStateChanged(subId=" + subId + ",state=" + simState + ")");
             switch(simState) {
                 // If the SIM is unlocked via a key sequence through the emergency dialer, it will
                 // move into the READY state and the PUK lock keyguard should be removed.
-                case READY: {
+                case TelephonyManager.SIM_STATE_READY: {
                     mRemainingAttempts = -1;
                     mShowDefaultMessage = true;
                     // mCallback can be null if onSimStateChanged callback is called when keyguard
@@ -210,7 +208,7 @@
 
     private void handleSubInfoChangeIfNeeded() {
         KeyguardUpdateMonitor monitor = Dependency.get(KeyguardUpdateMonitor.class);
-        int subId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
+        int subId = monitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PUK_REQUIRED);
         if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
             mSubId = subId;
             mShowDefaultMessage = true;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 0b0922a..1d4b9ef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -93,7 +93,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.widget.LockPatternUtils;
@@ -1055,7 +1054,7 @@
                 // and processed previously.
                 if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
                     // Guarantee mTelephonyCapable state after SysUI crash and restart
-                    if (args.simState == State.ABSENT) {
+                    if (args.simState == TelephonyManager.SIM_STATE_ABSENT) {
                         mHandler.obtainMessage(MSG_TELEPHONY_CAPABLE, true).sendToTarget();
                     }
                     return;
@@ -1226,18 +1225,18 @@
      * the intent and provide a {@link SimCard.State} result.
      */
     private static class SimData {
-        public State simState;
+        public int simState;
         public int slotId;
         public int subId;
 
-        SimData(State state, int slot, int id) {
+        SimData(int state, int slot, int id) {
             simState = state;
             slotId = slot;
             subId = id;
         }
 
         static SimData fromIntent(Intent intent) {
-            State state;
+            int state;
             if (!TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
                 throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED");
             }
@@ -1251,33 +1250,33 @@
 
                 if (IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED.equals(
                         absentReason)) {
-                    state = IccCardConstants.State.PERM_DISABLED;
+                    state = TelephonyManager.SIM_STATE_PERM_DISABLED;
                 } else {
-                    state = IccCardConstants.State.ABSENT;
+                    state = TelephonyManager.SIM_STATE_ABSENT;
                 }
             } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-                state = IccCardConstants.State.READY;
+                state = TelephonyManager.SIM_STATE_READY;
             } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
                 final String lockedReason = intent
                         .getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
                 if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                    state = IccCardConstants.State.PIN_REQUIRED;
+                    state = TelephonyManager.SIM_STATE_PIN_REQUIRED;
                 } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                    state = IccCardConstants.State.PUK_REQUIRED;
+                    state = TelephonyManager.SIM_STATE_PUK_REQUIRED;
                 } else {
-                    state = IccCardConstants.State.UNKNOWN;
+                    state = TelephonyManager.SIM_STATE_UNKNOWN;
                 }
             } else if (IccCardConstants.INTENT_VALUE_LOCKED_NETWORK.equals(stateExtra)) {
-                state = IccCardConstants.State.NETWORK_LOCKED;
+                state = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
             } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
-                state = IccCardConstants.State.CARD_IO_ERROR;
+                state = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
             } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(stateExtra)
                     || IccCardConstants.INTENT_VALUE_ICC_IMSI.equals(stateExtra)) {
                 // This is required because telephony doesn't return to "READY" after
                 // these state transitions. See bug 7197471.
-                state = IccCardConstants.State.READY;
+                state = TelephonyManager.SIM_STATE_READY;
             } else {
-                state = IccCardConstants.State.UNKNOWN;
+                state = TelephonyManager.SIM_STATE_UNKNOWN;
             }
             return new SimData(state, slotId, subId);
         }
@@ -1525,7 +1524,7 @@
                         handleBatteryUpdate((BatteryStatus) msg.obj);
                         break;
                     case MSG_SIM_STATE_CHANGE:
-                        handleSimStateChange(msg.arg1, msg.arg2, (State) msg.obj);
+                        handleSimStateChange(msg.arg1, msg.arg2, (int) msg.obj);
                         break;
                     case MSG_RINGER_MODE_CHANGED:
                         handleRingerModeChange(msg.arg1);
@@ -2260,7 +2259,7 @@
      * Handle {@link #MSG_SIM_STATE_CHANGE}
      */
     @VisibleForTesting
-    void handleSimStateChange(int subId, int slotId, State state) {
+    void handleSimStateChange(int subId, int slotId, int state) {
         checkIsHandlerThread();
         if (DEBUG_SIM_STATES) {
             Log.d(TAG, "handleSimStateChange(subId=" + subId + ", slotId="
@@ -2272,7 +2271,7 @@
             Log.w(TAG, "invalid subId in handleSimStateChange()");
             /* Only handle No SIM(ABSENT) and Card Error(CARD_IO_ERROR) due to
              * handleServiceStateChange() handle other case */
-            if (state == State.ABSENT) {
+            if (state == TelephonyManager.SIM_STATE_ABSENT) {
                 updateTelephonyCapable(true);
                 // Even though the subscription is not valid anymore, we need to notify that the
                 // SIM card was removed so we can update the UI.
@@ -2281,10 +2280,10 @@
                     // Set the SIM state of all SimData associated with that slot to ABSENT se we
                     // do not move back into PIN/PUK locked and not detect the change below.
                     if (data.slotId == slotId) {
-                        data.simState = State.ABSENT;
+                        data.simState = TelephonyManager.SIM_STATE_ABSENT;
                     }
                 }
-            } else if (state == State.CARD_IO_ERROR) {
+            } else if (state == TelephonyManager.SIM_STATE_CARD_IO_ERROR) {
                 updateTelephonyCapable(true);
             } else {
                 return;
@@ -2303,7 +2302,7 @@
             data.subId = subId;
             data.slotId = slotId;
         }
-        if ((changed || becameAbsent) && state != State.UNKNOWN) {
+        if ((changed || becameAbsent) && state != TelephonyManager.SIM_STATE_UNKNOWN) {
             for (int i = 0; i < mCallbacks.size(); i++) {
                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                 if (cb != null) {
@@ -2542,7 +2541,7 @@
     @MainThread
     public void reportSimUnlocked(int subId) {
         if (DEBUG_SIM_STATES) Log.v(TAG, "reportSimUnlocked(subId=" + subId + ")");
-        handleSimStateChange(subId, getSlotId(subId), State.READY);
+        handleSimStateChange(subId, getSlotId(subId), TelephonyManager.SIM_STATE_READY);
     }
 
     /**
@@ -2607,11 +2606,11 @@
         return false;
     }
 
-    public State getSimState(int subId) {
+    public int getSimState(int subId) {
         if (mSimDatas.containsKey(subId)) {
             return mSimDatas.get(subId).simState;
         } else {
-            return State.UNKNOWN;
+            return TelephonyManager.SIM_STATE_UNKNOWN;
         }
     }
 
@@ -2644,22 +2643,10 @@
      * @return true if and only if the state has changed for the specified {@code slotId}
      */
     private boolean refreshSimState(int subId, int slotId) {
-
-        // This is awful. It exists because there are two APIs for getting the SIM status
-        // that don't return the complete set of values and have different types. In Keyguard we
-        // need IccCardConstants, but TelephonyManager would only give us
-        // TelephonyManager.SIM_STATE*, so we retrieve it manually.
         final TelephonyManager tele =
             (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        int simState = (tele != null) ?
+        int state = (tele != null) ?
             tele.getSimState(slotId) : TelephonyManager.SIM_STATE_UNKNOWN;
-        State state;
-        try {
-            state = State.intToState(simState);
-        } catch (IllegalArgumentException ex) {
-            Log.w(TAG, "Unknown sim state: " + simState);
-            state = State.UNKNOWN;
-        }
         SimData data = mSimDatas.get(subId);
         final boolean changed;
         if (data == null) {
@@ -2676,10 +2663,10 @@
     /**
      * If the {@code state} is currently requiring a SIM PIN, PUK, or is disabled.
      */
-    public static boolean isSimPinSecure(IccCardConstants.State state) {
-        return (state == IccCardConstants.State.PIN_REQUIRED
-                || state == IccCardConstants.State.PUK_REQUIRED
-                || state == IccCardConstants.State.PERM_DISABLED);
+    public static boolean isSimPinSecure(int state) {
+        return (state == TelephonyManager.SIM_STATE_PIN_REQUIRED
+                || state == TelephonyManager.SIM_STATE_PUK_REQUIRED
+                || state == TelephonyManager.SIM_STATE_PERM_DISABLED);
     }
 
     public DisplayClientState getCachedDisplayClientState() {
@@ -2741,7 +2728,7 @@
      *
      * @return subid or {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} if none found
      */
-    public int getNextSubIdForState(State state) {
+    public int getNextSubIdForState(int state) {
         List<SubscriptionInfo> list = getSubscriptionInfo(false /* forceReload */);
         int resultId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         int bestSlotId = Integer.MAX_VALUE; // Favor lowest slot first
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 0fef755..b4b83d6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -23,7 +23,6 @@
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicyConstants;
 
-import com.android.internal.telephony.IccCardConstants;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 
 import java.util.TimeZone;
@@ -136,7 +135,7 @@
      * @param slotId
      * @param simState
      */
-    public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) { }
+    public void onSimStateChanged(int subId, int slotId, int simState) { }
 
     /**
      * Called when the user's info changed.
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index b3f32af..1a0690c 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -59,6 +59,7 @@
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.PrivacyItemController;
 import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.DevicePolicyManagerWrapper;
@@ -74,10 +75,10 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
 import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -92,6 +93,7 @@
 import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -123,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;
@@ -328,6 +331,9 @@
     @Inject Lazy<DozeParameters> mDozeParameters;
     @Inject Lazy<IWallpaperManager> mWallpaperManager;
     @Inject Lazy<CommandQueue> mCommandQueue;
+    @Inject Lazy<Recents> mRecents;
+    @Inject Lazy<StatusBar> mStatusBar;
+    @Inject Lazy<DisplayWindowController> mDisplayWindowController;
 
     @Inject
     public Dependency() {
@@ -517,6 +523,9 @@
         mProviders.put(DozeParameters.class, mDozeParameters::get);
         mProviders.put(IWallpaperManager.class, mWallpaperManager::get);
         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/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
index c2d090e..15a5c27 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java
@@ -16,6 +16,7 @@
 
 import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.util.ArraySet;
@@ -23,13 +24,13 @@
 
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.systemui.appops.AppOpsController;
+import com.android.systemui.dagger.qualifiers.MainHandler;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-
 /**
  * Tracks state of foreground services and notifications related to foreground services per user.
  */
@@ -44,12 +45,18 @@
     private final SparseArray<ForegroundServicesUserState> mUserServices = new SparseArray<>();
     private final Object mMutex = new Object();
     private final NotificationEntryManager mEntryManager;
+    private final Handler mMainHandler;
 
     @Inject
     public ForegroundServiceController(NotificationEntryManager entryManager,
-            AppOpsController appOpsController) {
+            AppOpsController appOpsController, @MainHandler Handler mainHandler) {
         mEntryManager = entryManager;
-        appOpsController.addCallback(APP_OPS, this::onAppOpChanged);
+        mMainHandler = mainHandler;
+        appOpsController.addCallback(APP_OPS, (code, uid, packageName, active) -> {
+            mMainHandler.post(() -> {
+                onAppOpChanged(code, uid, packageName, active);
+            });
+        });
     }
 
     /**
@@ -113,7 +120,7 @@
      * @param packageName package that created the notification
      * @param active whether the appOpCode is active or not
      */
-    public void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) {
+    void onAppOpChanged(int appOpCode, int uid, String packageName, boolean active) {
         int userId = UserHandle.getUserId(uid);
         // Record active app ops
         synchronized (mMutex) {
@@ -132,7 +139,7 @@
         // Update appOp if there's an associated pending or visible notification:
         final String foregroundKey = getStandardLayoutKey(userId, packageName);
         if (foregroundKey != null) {
-            final NotificationEntry entry = mEntryManager.getPendingOrCurrentNotif(foregroundKey);
+            final NotificationEntry entry = mEntryManager.getPendingOrActiveNotif(foregroundKey);
             if (entry != null
                     && uid == entry.getSbn().getUid()
                     && packageName.equals(entry.getSbn().getPackageName())) {
diff --git a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
deleted file mode 100644
index ff4b7cb..0000000
--- a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.content.Context;
-
-/**
- * The interface for getting core components of SysUI. Exists for Testability
- * since tests don't have SystemUIApplication as their ApplicationContext.
- */
-public interface SysUiServiceProvider {
-    <T> T getComponent(Class<T> interfaceType);
-
-    public static <T> T getComponent(Context context, Class<T> interfaceType) {
-        return ((SysUiServiceProvider) context.getApplicationContext()).getComponent(interfaceType);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index 7570037..f795faf 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -23,11 +23,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.Map;
 
-public abstract class SystemUI implements SysUiServiceProvider {
+public abstract class SystemUI {
     protected final Context mContext;
-    public Map<Class<?>, Object> mComponents;
 
     public SystemUI(Context context) {
         mContext = context;
@@ -44,17 +42,6 @@
     protected void onBootCompleted() {
     }
 
-    @SuppressWarnings("unchecked")
-    public <T> T getComponent(Class<T> interfaceType) {
-        return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
-    }
-
-    public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
-        if (mComponents != null) {
-            mComponents.put(interfaceType, component);
-        }
-    }
-
     public static void overrideNotificationAppName(Context context, Notification.Builder n,
             boolean system) {
         final Bundle extras = new Bundle();
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index aab4041..f0317b4 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -36,13 +36,11 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
  * Application class for SystemUI.
  */
-public class SystemUIApplication extends Application implements SysUiServiceProvider,
+public class SystemUIApplication extends Application implements
         SystemUIAppComponentFactory.ContextInitializer {
 
     public static final String TAG = "SystemUIService";
@@ -56,7 +54,6 @@
     private SystemUI[] mServices;
     private boolean mServicesStarted;
     private boolean mBootCompleted;
-    private final Map<Class<?>, Object> mComponents = new HashMap<>();
     private SystemUIAppComponentFactory.ContextAvailableCallback mContextAvailableCallback;
 
     public SystemUIApplication() {
@@ -141,7 +138,7 @@
 
     public void startServicesIfNeeded() {
         String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);
-        startServicesIfNeeded(names);
+        startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
     }
 
     /**
@@ -153,10 +150,10 @@
     void startSecondaryUserServicesIfNeeded() {
         String[] names =
                   getResources().getStringArray(R.array.config_systemUIServiceComponentsPerUser);
-        startServicesIfNeeded(names);
+        startServicesIfNeeded(/* metricsPrefix= */ "StartSecondaryServices", names);
     }
 
-    private void startServicesIfNeeded(String[] services) {
+    private void startServicesIfNeeded(String metricsPrefix, String[] services) {
         if (mServicesStarted) {
             return;
         }
@@ -177,12 +174,12 @@
                 Process.myUserHandle().getIdentifier() + ".");
         TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
                 Trace.TRACE_TAG_APP);
-        log.traceBegin("StartServices");
+        log.traceBegin(metricsPrefix);
         final int N = services.length;
         for (int i = 0; i < N; i++) {
             String clsName = services[i];
             if (DEBUG) Log.d(TAG, "loading: " + clsName);
-            log.traceBegin("StartServices" + clsName);
+            log.traceBegin(metricsPrefix + clsName);
             long ti = System.currentTimeMillis();
             try {
                 SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
@@ -199,7 +196,6 @@
                 throw new RuntimeException(ex);
             }
 
-            mServices[i].mComponents = mComponents;
             if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
             mServices[i].start();
             log.traceEnd();
@@ -232,11 +228,6 @@
         }
     }
 
-    @SuppressWarnings("unchecked")
-    public <T> T getComponent(Class<T> interfaceType) {
-        return (T) mComponents.get(interfaceType);
-    }
-
     public SystemUI[] getServices() {
         return mServices;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index f616d57..139bfd5 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 
@@ -77,12 +78,14 @@
     };
 
     @Inject
-    public AppOpsControllerImpl(Context context, @BgLooper Looper bgLooper) {
-        this(context, bgLooper, new PermissionFlagsCache(context));
+    public AppOpsControllerImpl(Context context, @BgLooper Looper bgLooper,
+            DumpController dumpController) {
+        this(context, bgLooper, new PermissionFlagsCache(context), dumpController);
     }
 
     @VisibleForTesting
-    protected AppOpsControllerImpl(Context context, Looper bgLooper, PermissionFlagsCache cache) {
+    protected AppOpsControllerImpl(Context context, Looper bgLooper, PermissionFlagsCache cache,
+            DumpController dumpController) {
         mContext = context;
         mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mFlagsCache = cache;
@@ -91,6 +94,7 @@
         for (int i = 0; i < numOps; i++) {
             mCallbacksByCode.put(OPS[i], new ArraySet<>());
         }
+        dumpController.registerDumpable(TAG, this);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
index 4516996..170c25a 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleBehaviorController.java
@@ -71,7 +71,7 @@
     private final Runnable mHideHandles = this::hideHandles;
     private final Runnable mShowAndGo = this::showAndGoInternal;
     private final Provider<AssistHandleViewController> mAssistHandleViewController;
-    private final PhenotypeHelper mPhenotypeHelper;
+    private final DeviceConfigHelper mDeviceConfigHelper;
     private final Map<AssistHandleBehavior, BehaviorController> mBehaviorMap;
 
     private boolean mHandlesShowing = false;
@@ -90,7 +90,7 @@
             AssistUtils assistUtils,
             @Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
             Provider<AssistHandleViewController> assistHandleViewController,
-            PhenotypeHelper phenotypeHelper,
+            DeviceConfigHelper deviceConfigHelper,
             Map<AssistHandleBehavior, BehaviorController> behaviorMap,
             NavigationModeController navigationModeController,
             DumpController dumpController) {
@@ -98,14 +98,14 @@
         mAssistUtils = assistUtils;
         mHandler = handler;
         mAssistHandleViewController = assistHandleViewController;
-        mPhenotypeHelper = phenotypeHelper;
+        mDeviceConfigHelper = deviceConfigHelper;
         mBehaviorMap = behaviorMap;
 
         mInGesturalMode = QuickStepContract.isGesturalMode(
                 navigationModeController.addListener(this::handleNavigationModeChange));
 
         setBehavior(getBehaviorMode());
-        mPhenotypeHelper.addOnPropertiesChangedListener(
+        mDeviceConfigHelper.addOnPropertiesChangedListener(
                 mHandler::post,
                 (properties) -> {
                     if (properties.getKeyset().contains(
@@ -205,19 +205,19 @@
     }
 
     private long getShownFrequencyThreshold() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS,
                 DEFAULT_SHOWN_FREQUENCY_THRESHOLD_MS);
     }
 
     private long getShowAndGoDuration() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DURATION_MS,
                 DEFAULT_SHOW_AND_GO_DURATION_MS);
     }
 
     private String getBehaviorMode() {
-        return mPhenotypeHelper.getString(
+        return mDeviceConfigHelper.getString(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_BEHAVIOR_MODE,
                 DEFAULT_BEHAVIOR.toString());
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 46ae84a..9793d72 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -155,7 +155,7 @@
 
     private final Clock mClock;
     private final Handler mHandler;
-    private final PhenotypeHelper mPhenotypeHelper;
+    private final DeviceConfigHelper mDeviceConfigHelper;
     private final Lazy<StatusBarStateController> mStatusBarStateController;
     private final Lazy<ActivityManagerWrapper> mActivityManagerWrapper;
     private final Lazy<OverviewProxyService> mOverviewProxyService;
@@ -189,7 +189,7 @@
     AssistHandleReminderExpBehavior(
             @Named(UPTIME_NAME) Clock clock,
             @Named(ASSIST_HANDLE_THREAD_NAME) Handler handler,
-            PhenotypeHelper phenotypeHelper,
+            DeviceConfigHelper deviceConfigHelper,
             Lazy<StatusBarStateController> statusBarStateController,
             Lazy<ActivityManagerWrapper> activityManagerWrapper,
             Lazy<OverviewProxyService> overviewProxyService,
@@ -199,7 +199,7 @@
             Lazy<BroadcastDispatcher> broadcastDispatcher) {
         mClock = clock;
         mHandler = handler;
-        mPhenotypeHelper = phenotypeHelper;
+        mDeviceConfigHelper = deviceConfigHelper;
         mStatusBarStateController = statusBarStateController;
         mActivityManagerWrapper = activityManagerWrapper;
         mOverviewProxyService = overviewProxyService;
@@ -465,55 +465,55 @@
     }
 
     private long getLearningTimeMs() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_TIME_MS,
                 DEFAULT_LEARNING_TIME_MS);
     }
 
     private int getLearningCount() {
-        return mPhenotypeHelper.getInt(
+        return mDeviceConfigHelper.getInt(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_LEARN_COUNT,
                 DEFAULT_LEARNING_COUNT);
     }
 
     private long getShowAndGoDelayedShortDelayMs() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS,
                 DEFAULT_SHOW_AND_GO_DELAYED_SHORT_DELAY_MS);
     }
 
     private long getShowAndGoDelayedLongDelayMs() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAYED_LONG_DELAY_MS,
                 DEFAULT_SHOW_AND_GO_DELAYED_LONG_DELAY_MS);
     }
 
     private long getShowAndGoDelayResetTimeoutMs() {
-        return mPhenotypeHelper.getLong(
+        return mDeviceConfigHelper.getLong(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS,
                 DEFAULT_SHOW_AND_GO_DELAY_RESET_TIMEOUT_MS);
     }
 
     private boolean getSuppressOnLockscreen() {
-        return mPhenotypeHelper.getBoolean(
+        return mDeviceConfigHelper.getBoolean(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LOCKSCREEN,
                 DEFAULT_SUPPRESS_ON_LOCKSCREEN);
     }
 
     private boolean getSuppressOnLauncher() {
-        return mPhenotypeHelper.getBoolean(
+        return mDeviceConfigHelper.getBoolean(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_LAUNCHER,
                 DEFAULT_SUPPRESS_ON_LAUNCHER);
     }
 
     private boolean getSuppressOnApps() {
-        return mPhenotypeHelper.getBoolean(
+        return mDeviceConfigHelper.getBoolean(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SUPPRESS_ON_APPS,
                 DEFAULT_SUPPRESS_ON_APPS);
     }
 
     private boolean getShowWhenTaught() {
-        return mPhenotypeHelper.getBoolean(
+        return mDeviceConfigHelper.getBoolean(
                 SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOW_WHEN_TAUGHT,
                 DEFAULT_SHOW_WHEN_TAUGHT);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 398826c..dd00eee 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -42,10 +42,8 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.settingslib.applications.InterestingConfigChanges;
 import com.android.systemui.ConfigurationChangedReceiver;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.assist.ui.DefaultUiController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -163,14 +161,15 @@
             AssistUtils assistUtils,
             AssistHandleBehaviorController handleController,
             CommandQueue commandQueue,
-            BroadcastDispatcher broadcastDispatcher) {
+            PhoneStateMonitor phoneStateMonitor,
+            OverviewProxyService overviewProxyService) {
         mContext = context;
         mDeviceProvisionedController = controller;
         mCommandQueue = commandQueue;
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mAssistUtils = assistUtils;
         mAssistDisclosure = new AssistDisclosure(context, new Handler());
-        mPhoneStateMonitor = new PhoneStateMonitor(context, broadcastDispatcher);
+        mPhoneStateMonitor = phoneStateMonitor;
         mHandleController = handleController;
 
         registerVoiceInteractionSessionListener();
@@ -182,8 +181,7 @@
 
         mUiController = new DefaultUiController(mContext);
 
-        OverviewProxyService overviewProxy = Dependency.get(OverviewProxyService.class);
-        overviewProxy.addCallback(new OverviewProxyService.OverviewProxyListener() {
+        overviewProxyService.addCallback(new OverviewProxyService.OverviewProxyListener() {
             @Override
             public void onAssistantProgress(float progress) {
                 // Progress goes from 0 to 1 to indicate how close the assist gesture is to
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java b/packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
rename to packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java
index cbb56e8..86b7c74 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhenotypeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/DeviceConfigHelper.java
@@ -28,15 +28,15 @@
 import javax.inject.Singleton;
 
 /**
- * Wrapper class for retrieving phenotype flag values.
+ * Wrapper class for retrieving System UI device configuration values.
  *
  * Can be mocked in tests for ease of testing the effects of particular values.
  */
 @Singleton
-public class PhenotypeHelper {
+public class DeviceConfigHelper {
 
     @Inject
-    public PhenotypeHelper() {}
+    public DeviceConfigHelper() {}
 
     public long getLong(String name, long defaultValue) {
         return whitelistIpcs(() ->
@@ -64,4 +64,9 @@
         DeviceConfig.addOnPropertiesChangedListener(
                 DeviceConfig.NAMESPACE_SYSTEMUI, executor, listener);
     }
+
+    public void removeOnPropertiesChangedListener(
+            DeviceConfig.OnPropertiesChangedListener listener) {
+        DeviceConfig.removeOnPropertiesChangedListener(listener);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 95d611a..8cccffa 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -28,7 +28,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.systemui.Dependency;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -39,9 +38,16 @@
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import dagger.Lazy;
 
 /** Class to monitor and report the state of the phone. */
-final class PhoneStateMonitor {
+@Singleton
+public final class PhoneStateMonitor {
 
     private static final int PHONE_STATE_AOD1 = 1;
     private static final int PHONE_STATE_AOD2 = 2;
@@ -63,13 +69,17 @@
     };
 
     private final Context mContext;
+    private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
     private final StatusBarStateController mStatusBarStateController;
 
     private boolean mLauncherShowing;
     @Nullable private ComponentName mDefaultHome;
 
-    PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher) {
+    @Inject
+    PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher,
+            Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
         mContext = context;
+        mStatusBarOptionalLazy = statusBarOptionalLazy;
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
 
         ActivityManagerWrapper activityManagerWrapper = ActivityManagerWrapper.getInstance();
@@ -178,16 +188,16 @@
     }
 
     private boolean isAppImmersive() {
-        return SysUiServiceProvider.getComponent(mContext, StatusBar.class).inImmersiveMode();
+        return mStatusBarOptionalLazy.get().get().inImmersiveMode();
     }
 
     private boolean isAppFullscreen() {
-        return SysUiServiceProvider.getComponent(mContext, StatusBar.class).inFullscreenMode();
+        return mStatusBarOptionalLazy.get().get().inFullscreenMode();
     }
 
     private boolean isBouncerShowing() {
-        StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        return statusBar != null && statusBar.isBouncerShowing();
+        return mStatusBarOptionalLazy.map(
+                statusBarLazy -> statusBarLazy.get().isBouncerShowing()).orElse(false);
     }
 
     private boolean isKeyguardLocked() {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index f8e45d4..c6b9090 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -64,7 +64,8 @@
 
     private long mLastUpdated;
     private long mLastAccessed;
-    private boolean mIsRemoved;
+
+    private boolean mIsUserCreated;
 
     /**
      * Whether this notification should be shown in the shade when it is also displayed as a bubble.
@@ -74,9 +75,7 @@
      */
     private boolean mShowInShadeWhenBubble = true;
 
-    /**
-     * Whether the bubble should show a dot for the notification indicating updated content.
-     */
+    /** Whether the bubble should show a dot for the notification indicating updated content. */
     private boolean mShowBubbleUpdateDot = true;
 
     /** Whether flyout text should be suppressed, regardless of any other flags or state. */
@@ -294,6 +293,20 @@
         return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
     }
 
+    /**
+     * Whether this bubble was explicitly created by the user via a SysUI affordance.
+     */
+    boolean isUserCreated() {
+        return mIsUserCreated;
+    }
+
+    /**
+     * Set whether this bubble was explicitly created by the user via a SysUI affordance.
+     */
+    void setUserCreated(boolean isUserCreated) {
+        mIsUserCreated = isUserCreated;
+    }
+
     float getDesiredHeight(Context context) {
         Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
         boolean useRes = data.getDesiredHeightResId() != 0;
@@ -319,9 +332,8 @@
 
     @Nullable
     PendingIntent getBubbleIntent(Context context) {
-        Notification notif = mEntry.getSbn().getNotification();
-        Notification.BubbleMetadata data = notif.getBubbleMetadata();
-        if (BubbleController.canLaunchInActivityView(context, mEntry) && data != null) {
+        Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
+        if (data != null) {
             return data.getIntent();
         }
         return null;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 0231b56..db1185f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -47,6 +47,7 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -67,7 +68,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.IStatusBarService;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -79,9 +79,10 @@
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -96,6 +97,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Bubbles are a special type of content that can "float" on top of other apps or System UI.
  * Bubbles can be expanded to show more content.
@@ -132,6 +135,7 @@
     private BubbleExpandListener mExpandListener;
     @Nullable private BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
     private final NotificationGroupManager mNotificationGroupManager;
+    private final Lazy<ShadeController> mShadeController;
 
     private BubbleData mBubbleData;
     @Nullable private BubbleStackView mStackView;
@@ -206,24 +210,34 @@
     }
 
     @Inject
-    public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data, ConfigurationController configurationController,
-            NotificationInterruptionStateProvider interruptionStateProvider,
-            ZenModeController zenModeController,
-            NotificationLockscreenUserManager notifUserManager,
-            NotificationGroupManager groupManager) {
-        this(context, statusBarWindowController, data, null /* synchronizer */,
-                configurationController, interruptionStateProvider, zenModeController,
-                notifUserManager, groupManager);
-    }
-
-    public BubbleController(Context context, StatusBarWindowController statusBarWindowController,
-            BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+    public BubbleController(Context context,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarStateController statusBarStateController,
+            Lazy<ShadeController> shadeController,
+            BubbleData data,
             ConfigurationController configurationController,
             NotificationInterruptionStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
-            NotificationGroupManager groupManager) {
+            NotificationGroupManager groupManager,
+            NotificationEntryManager entryManager) {
+        this(context, statusBarWindowController, statusBarStateController, shadeController,
+                data, null /* synchronizer */, configurationController, interruptionStateProvider,
+                zenModeController, notifUserManager, groupManager, entryManager);
+    }
+
+    public BubbleController(Context context,
+            StatusBarWindowController statusBarWindowController,
+            StatusBarStateController statusBarStateController,
+            Lazy<ShadeController> shadeController,
+            BubbleData data,
+            @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
+            ConfigurationController configurationController,
+            NotificationInterruptionStateProvider interruptionStateProvider,
+            ZenModeController zenModeController,
+            NotificationLockscreenUserManager notifUserManager,
+            NotificationGroupManager groupManager,
+            NotificationEntryManager entryManager) {
         mContext = context;
         mNotificationInterruptionStateProvider = interruptionStateProvider;
         mNotifUserManager = notifUserManager;
@@ -249,7 +263,7 @@
         mBubbleData = data;
         mBubbleData.setListener(mBubbleDataListener);
 
-        mNotificationEntryManager = Dependency.get(NotificationEntryManager.class);
+        mNotificationEntryManager = entryManager;
         mNotificationEntryManager.addNotificationEntryListener(mEntryListener);
         mNotificationEntryManager.setNotificationRemoveInterceptor(mRemoveInterceptor);
         mNotificationGroupManager = groupManager;
@@ -271,9 +285,10 @@
                     }
                 });
 
+        mShadeController = shadeController;
         mStatusBarWindowController = statusBarWindowController;
         mStatusBarStateListener = new StatusBarStateListener();
-        Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
+        statusBarStateController.addCallback(mStatusBarStateListener);
 
         mTaskStackListener = new BubbleTaskStackListener();
         ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
@@ -338,14 +353,13 @@
      * @param userId the id of the user
      */
     private void restoreBubbles(@UserIdInt int userId) {
-        NotificationData notificationData =
-                mNotificationEntryManager.getNotificationData();
         ArraySet<String> savedBubbleKeys = mSavedBubbleKeysPerUser.get(userId);
         if (savedBubbleKeys == null) {
             // There were no bubbles saved for this used.
             return;
         }
-        for (NotificationEntry e : notificationData.getNotificationsForCurrentUser()) {
+        for (NotificationEntry e :
+                mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
             if (savedBubbleKeys.contains(e.getKey())
                     && mNotificationInterruptionStateProvider.shouldBubbleUp(e)
                     && canLaunchInActivityView(mContext, e)) {
@@ -444,7 +458,7 @@
     public boolean isBubbleNotificationSuppressedFromShade(String key) {
         boolean isBubbleAndSuppressed = mBubbleData.hasBubbleWithKey(key)
                 && !mBubbleData.getBubbleWithKey(key).showInShadeWhenBubble();
-        NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+        NotificationEntry entry = mNotificationEntryManager.getActiveNotificationUnfiltered(key);
         String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
         boolean isSuppressedSummary = mBubbleData.isSummarySuppressed(groupKey);
         boolean isSummary = key.equals(mBubbleData.getSummaryKey(groupKey));
@@ -497,15 +511,45 @@
      * @param notif the notification associated with this bubble.
      */
     void updateBubble(NotificationEntry notif) {
-        updateBubble(notif, /* supressFlyout */ false);
+        updateBubble(notif, false /* suppressFlyout */);
     }
 
     void updateBubble(NotificationEntry notif, boolean suppressFlyout) {
+        updateBubble(notif, suppressFlyout, true /* showInShade */);
+    }
+
+    void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) {
         // If this is an interruptive notif, mark that it's interrupted
         if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) {
             notif.setInterruption();
         }
-        mBubbleData.notificationEntryUpdated(notif, suppressFlyout);
+        mBubbleData.notificationEntryUpdated(notif, suppressFlyout, showInShade);
+    }
+
+    /**
+     * Called when a user has indicated that an active notification should be shown as a bubble.
+     * <p>
+     * This method will collapse the shade, create the bubble without a flyout or dot, and suppress
+     * the notification from appearing in the shade.
+     *
+     * @param entry the notification to show as a bubble.
+     */
+    public void onUserCreatedBubbleFromNotification(NotificationEntry entry) {
+        mShadeController.get().collapsePanel(true);
+        entry.setFlagBubble(true);
+        updateBubble(entry, true /* suppressFlyout */, false /* showInShade */);
+        mBubbleData.getBubbleWithKey(entry.getKey()).setUserCreated(true);
+    }
+
+    /**
+     * Called when a user has indicated that an active notification appearing as a bubble should
+     * no longer be shown as a bubble.
+     *
+     * @param entry the notification to no longer show as a bubble.
+     */
+    public void onUserDemotedBubbleFromNotification(NotificationEntry entry) {
+        entry.setFlagBubble(false);
+        removeBubble(entry.getKey(), DISMISS_BLOCKED);
     }
 
     /**
@@ -527,7 +571,8 @@
             new NotificationRemoveInterceptor() {
             @Override
             public boolean onNotificationRemoveRequested(String key, int reason) {
-                NotificationEntry entry = mNotificationEntryManager.getNotificationData().get(key);
+                NotificationEntry entry =
+                        mNotificationEntryManager.getActiveNotificationUnfiltered(key);
                 String groupKey = entry != null ? entry.getSbn().getGroupKey() : null;
                 ArrayList<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey);
 
@@ -571,7 +616,7 @@
                     mNotificationEntryManager.updateNotifications(
                             "BubbleController.onNotificationRemoveRequested");
                     return true;
-                } else if (!userRemovedNotif && entry != null) {
+                } else if (!userRemovedNotif && entry != null && !bubble.isUserCreated()) {
                     // This wasn't a user removal so we should remove the bubble as well
                     mBubbleData.notificationEntryRemoved(entry, DISMISS_NOTIF_CANCEL);
                     return false;
@@ -631,6 +676,9 @@
     private final NotificationEntryListener mEntryListener = new NotificationEntryListener() {
         @Override
         public void onPendingEntryAdded(NotificationEntry entry) {
+            Bubble b = mBubbleData.getBubbleWithKey(entry.getKey());
+            BubbleExperimentConfig.adjustForExperiments(mContext, entry, b);
+
             if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
                     && canLaunchInActivityView(mContext, entry)) {
                 updateBubble(entry);
@@ -639,13 +687,15 @@
 
         @Override
         public void onPreEntryUpdated(NotificationEntry entry) {
+            Bubble b = mBubbleData.getBubbleWithKey(entry.getKey());
+            BubbleExperimentConfig.adjustForExperiments(mContext, entry, b);
+
             boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
                     && canLaunchInActivityView(mContext, entry);
             if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
                 // It was previously a bubble but no longer a bubble -- lets remove it
                 removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE);
             } else if (shouldBubble) {
-                Bubble b = mBubbleData.getBubbleWithKey(entry.getKey());
                 updateBubble(entry);
             }
         }
@@ -719,7 +769,7 @@
                         String notifKey = mBubbleData.getSummaryKey(groupKey);
                         mBubbleData.removeSuppressedSummary(groupKey);
                         NotificationEntry entry =
-                                mNotificationEntryManager.getNotificationData().get(notifKey);
+                                mNotificationEntryManager.getActiveNotificationUnfiltered(notifKey);
                         mNotificationEntryManager.performRemoveNotification(
                                 entry.getSbn(), UNDEFINED_DISMISS_REASON);
                     }
@@ -949,19 +999,28 @@
         PendingIntent intent = entry.getBubbleMetadata() != null
                 ? entry.getBubbleMetadata().getIntent()
                 : null;
+        return canLaunchIntentInActivityView(context, entry, intent);
+    }
+
+    static boolean canLaunchIntentInActivityView(Context context, NotificationEntry entry,
+            PendingIntent intent) {
         if (intent == null) {
-            Log.w(TAG, "Unable to create bubble -- no intent");
+            Log.w(TAG, "Unable to create bubble -- no intent: " + entry.getKey());
             return false;
         }
+        PackageManager packageManager = StatusBar.getPackageManagerForUser(
+                context, entry.getSbn().getUser().getIdentifier());
         ActivityInfo info =
-                intent.getIntent().resolveActivityInfo(context.getPackageManager(), 0);
+                intent.getIntent().resolveActivityInfo(packageManager, 0);
         if (info == null) {
-            Log.w(TAG, "Unable to send as bubble -- couldn't find activity info for intent: "
+            Log.w(TAG, "Unable to send as bubble, "
+                    + entry.getKey() + " couldn't find activity info for intent: "
                     + intent);
             return false;
         }
         if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
-            Log.w(TAG, "Unable to send as bubble -- activity is not resizable for intent: "
+            Log.w(TAG, "Unable to send as bubble, "
+                    + entry.getKey() + " activity is not resizable for intent: "
                     + intent);
             return false;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index 4e229c0..2ca993b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -179,12 +179,14 @@
         dispatchPendingChanges();
     }
 
-    void notificationEntryUpdated(NotificationEntry entry, boolean suppressFlyout) {
+    void notificationEntryUpdated(NotificationEntry entry, boolean suppressFlyout,
+            boolean showInShade) {
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "notificationEntryUpdated: " + entry);
         }
+
         Bubble bubble = getBubbleWithKey(entry.getKey());
-        suppressFlyout = !entry.getRanking().visuallyInterruptive() || suppressFlyout;
+        suppressFlyout |= !shouldShowFlyout(entry);
 
         if (bubble == null) {
             // Create a new bubble
@@ -208,7 +210,7 @@
             setSelectedBubbleInternal(bubble);
         }
         boolean isBubbleExpandedAndSelected = mExpanded && mSelectedBubble == bubble;
-        bubble.setShowInShadeWhenBubble(!isBubbleExpandedAndSelected);
+        bubble.setShowInShadeWhenBubble(!isBubbleExpandedAndSelected && showInShade);
         bubble.setShowBubbleDot(!isBubbleExpandedAndSelected);
         dispatchPendingChanges();
     }
@@ -297,6 +299,15 @@
         return bubbleChildren;
     }
 
+    private boolean shouldShowFlyout(NotificationEntry notif) {
+        if (notif.getRanking().visuallyInterruptive()) {
+            return true;
+        }
+        final boolean suppressedFromShade = hasBubbleWithKey(notif.getKey())
+                && !getBubbleWithKey(notif.getKey()).showInShadeWhenBubble();
+        return suppressedFromShade;
+    }
+
     private void doAdd(Bubble bubble) {
         if (DEBUG_BUBBLE_DATA) {
             Log.d(TAG, "doAdd: " + bubble);
@@ -509,7 +520,7 @@
      * required to keep grouping intact.
      *
      * @param minPosition the first insert point to consider
-     * @param newBubble the bubble to insert
+     * @param newBubble   the bubble to insert
      * @return the position where the bubble was inserted
      */
     private int insertBubble(int minPosition, Bubble newBubble) {
@@ -682,15 +693,19 @@
      * Description of current bubble data state.
      */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.print("selected: "); pw.println(mSelectedBubble != null
+        pw.print("selected: ");
+        pw.println(mSelectedBubble != null
                 ? mSelectedBubble.getKey()
                 : "null");
-        pw.print("expanded: "); pw.println(mExpanded);
-        pw.print("count:    "); pw.println(mBubbles.size());
+        pw.print("expanded: ");
+        pw.println(mExpanded);
+        pw.print("count:    ");
+        pw.println(mBubbles.size());
         for (Bubble bubble : mBubbles) {
             bubble.dump(fd, pw, args);
         }
-        pw.print("summaryKeys: "); pw.println(mSuppressedGroupKeys.size());
+        pw.print("summaryKeys: ");
+        pw.println(mSuppressedGroupKeys.size());
         for (String key : mSuppressedGroupKeys.keySet()) {
             pw.println("   suppressing: " + key);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index 1d9f6b2..e9c19d2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -184,10 +184,12 @@
                         + " mActivityViewStatus=" + mActivityViewStatus
                         + " bubble=" + getBubbleKey());
             }
-            if (mBubble != null) {
-                // Must post because this is called from a binder thread.
-                post(() -> mBubbleController.removeBubble(mBubble.getKey(),
-                        BubbleController.DISMISS_TASK_FINISHED));
+            if (mBubble != null && !mBubble.isUserCreated()) {
+                if (mBubble != null) {
+                    // Must post because this is called from a binder thread.
+                    post(() -> mBubbleController.removeBubble(mBubble.getKey(),
+                            BubbleController.DISMISS_TASK_FINISHED));
+                }
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
new file mode 100644
index 0000000..b478a72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -0,0 +1,98 @@
+/*
+ * 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.bubbles;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.drawable.Icon;
+import android.provider.Settings;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Common class for experiments controlled via secure settings.
+ */
+public class BubbleExperimentConfig {
+
+    private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble";
+    private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
+
+    private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
+    private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
+
+    /**
+     * When true, if a notification has the information necessary to bubble (i.e. valid
+     * contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
+     * object will be created by the system and added to the notification.
+     *
+     * This does not produce a bubble, only adds the metadata. It should be used in conjunction
+     * with {@see #allowNotifBubbleMenu} which shows an affordance to bubble notification content.
+     */
+    static boolean allowAnyNotifToBubble(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_ANY_NOTIF_TO_BUBBLE,
+                ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
+     * Same as {@link #allowAnyNotifToBubble(Context)} except it filters for notifications that
+     * are using {@link Notification.MessagingStyle} and have remote input.
+     */
+    static boolean allowMessageNotifsToBubble(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
+                ALLOW_MESSAGE_NOTIFS_TO_BUBBLE,
+                ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
+    }
+
+    /**
+     * If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
+     * {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
+     * the notification has necessary info for BubbleMetadata.
+     */
+    static void adjustForExperiments(Context context, NotificationEntry entry,
+            Bubble previousBubble) {
+        if (entry.getBubbleMetadata() != null) {
+            // Has metadata, nothing to do.
+            return;
+        }
+
+        Notification notification = entry.getSbn().getNotification();
+        boolean isMessage = Notification.MessagingStyle.class.equals(
+                notification.getNotificationStyle());
+        boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context))
+                || allowAnyNotifToBubble(context);
+
+        final PendingIntent intent = notification.contentIntent;
+        if (bubbleNotifForExperiment
+                && BubbleController.canLaunchIntentInActivityView(context, entry, intent)) {
+            final Icon smallIcon = entry.getSbn().getNotification().getSmallIcon();
+            Notification.BubbleMetadata.Builder metadata =
+                    new Notification.BubbleMetadata.Builder()
+                            .setDesiredHeight(10000)
+                            .setIcon(smallIcon)
+                            .setIntent(intent);
+            entry.setBubbleMetadata(metadata.build());
+        }
+
+        if (previousBubble != null) {
+            // Update to a previously user-created bubble, set its flag now so the update goes
+            // to the bubble.
+            entry.setFlagBubble(true);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 9032c6f..6744d74 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -72,6 +72,8 @@
 import com.android.systemui.statusbar.policy.ZenModeControllerImpl;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerServiceImpl;
+import com.android.systemui.volume.VolumeComponent;
+import com.android.systemui.volume.VolumeDialogComponent;
 import com.android.systemui.volume.VolumeDialogControllerImpl;
 
 import dagger.Binds;
@@ -249,4 +251,10 @@
      */
     @Binds
     public abstract DozeHost provideDozeHost(DozeServiceHost dozeServiceHost);
+
+    /**
+     */
+    @Binds
+    public abstract VolumeComponent provideVolumeComponent(
+            VolumeDialogComponent volumeDialogComponent);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index f86aaf1..f44eae7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -25,6 +25,7 @@
 
 import com.android.systemui.dock.DockManager;
 import com.android.systemui.dock.DockManagerImpl;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.recents.Recents;
@@ -33,15 +34,21 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+import java.util.Optional;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 import dagger.Binds;
+import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
@@ -71,7 +78,7 @@
     abstract DockManager bindDockManager(DockManagerImpl dockManager);
 
     @Binds
-    abstract NotificationData.KeyguardEnvironment bindKeyguardEnvironment(
+    abstract NotificationEntryManager.KeyguardEnvironment bindKeyguardEnvironment(
             KeyguardEnvironmentImpl keyguardEnvironment);
 
     @Binds
@@ -86,10 +93,21 @@
 
     @Singleton
     @Provides
-    static Divider provideDivider(Context context) {
-        return new Divider(context);
+    static Divider provideDivider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy) {
+        return new Divider(context, recentsOptionalLazy);
     }
 
+    @Singleton
+    @Provides
+    static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context,
+            StatusBarStateController statusBarStateController,
+            KeyguardBypassController bypassController) {
+        return new HeadsUpManagerPhone(context, statusBarStateController, bypassController);
+    }
+
+    @Binds
+    abstract HeadsUpManager bindHeadsUpManagerPhone(HeadsUpManagerPhone headsUpManagerPhone);
+
     @Provides
     @Singleton
     static Recents provideRecents(Context context, RecentsImplementation recentsImplementation,
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 6ae21b3..0ac158d 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -28,10 +28,15 @@
 import com.android.systemui.recents.Recents;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
 import com.android.systemui.statusbar.notification.people.PeopleHubModule;
 import com.android.systemui.statusbar.phone.KeyguardLiftController;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.util.sensors.AsyncSensorManager;
+import com.android.systemui.util.time.SystemClock;
+import com.android.systemui.util.time.SystemClockImpl;
 
 import javax.inject.Singleton;
 
@@ -80,8 +85,19 @@
     abstract Divider optionalDivider();
 
     @BindsOptionalOf
+    abstract HeadsUpManager optionalHeadsUpManager();
+
+    @BindsOptionalOf
     abstract Recents optionalRecents();
 
     @BindsOptionalOf
     abstract StatusBar optionalStatusBar();
+
+    @Singleton
+    @Binds
+    abstract SystemClock bindSystemClock(SystemClockImpl systemClock);
+
+    @Singleton
+    @Binds
+    abstract NotifListBuilder bindNotifListBuilder(NotifListBuilderImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
index d332f59..5239082 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManager.java
@@ -53,6 +53,11 @@
     */
     boolean isDocked();
 
+    /**
+     * Returns true if it is hiding docking UI.
+     */
+    boolean isHidden();
+
     /** Callback for receiving dock events */
     interface DockEventListener {
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java b/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
index fa7f503..f770910 100644
--- a/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/dock/DockManagerImpl.java
@@ -38,4 +38,9 @@
     public boolean isDocked() {
         return false;
     }
+
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index 419fd62..c16dce1 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -16,9 +16,7 @@
 
 package com.android.systemui.doze;
 
-import android.content.Context;
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
 import android.os.UserHandle;
 import android.util.Log;
 
@@ -35,23 +33,19 @@
     private static final String TAG = "DozeDockHandler";
     private static final boolean DEBUG = DozeService.DEBUG;
 
-    private final DozeMachine mMachine;
-    private final DozeHost mDozeHost;
     private final AmbientDisplayConfiguration mConfig;
-    private final Handler mHandler;
-    private final DockEventListener mDockEventListener = new DockEventListener();
+    private final DozeMachine mMachine;
     private final DockManager mDockManager;
+    private final DockEventListener mDockEventListener;
 
     private int mDockState = DockManager.STATE_NONE;
-    private boolean mPulsePending;
 
-    public DozeDockHandler(Context context, DozeMachine machine, DozeHost dozeHost,
-            AmbientDisplayConfiguration config, Handler handler, DockManager dockManager) {
+    public DozeDockHandler(AmbientDisplayConfiguration config, DozeMachine machine,
+            DockManager dockManager) {
         mMachine = machine;
-        mDozeHost = dozeHost;
         mConfig = config;
-        mHandler = handler;
         mDockManager = dockManager;
+        mDockEventListener = new DockEventListener();
     }
 
     @Override
@@ -60,18 +54,6 @@
             case INITIALIZED:
                 mDockEventListener.register();
                 break;
-            case DOZE_AOD:
-                if (mDockState == DockManager.STATE_DOCKED_HIDE) {
-                    mMachine.requestState(State.DOZE);
-                    break;
-                }
-                // continue below
-            case DOZE:
-                if (mDockState == DockManager.STATE_DOCKED && !mPulsePending) {
-                    mPulsePending = true;
-                    mHandler.post(() -> requestPulse(newState));
-                }
-                break;
             case FINISH:
                 mDockEventListener.unregister();
                 break;
@@ -80,64 +62,36 @@
         }
     }
 
-    private void requestPulse(State dozeState) {
-        if (!mDozeHost.isPulsingBlocked() && dozeState.canPulse()) {
-            mMachine.requestPulse(DozeEvent.PULSE_REASON_DOCKING);
-        }
-        mPulsePending = false;
-    }
-
-    private void requestPulseOutNow(State dozeState) {
-        if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING
-                || dozeState == State.DOZE_PULSING_BRIGHT) {
-            final int pulseReason = mMachine.getPulseReason();
-            if (pulseReason == DozeEvent.PULSE_REASON_DOCKING) {
-                mDozeHost.stopPulsing();
-            }
-        }
-    }
-
-    private boolean isDocked() {
-        return mDockState == DockManager.STATE_DOCKED
-                || mDockState == DockManager.STATE_DOCKED_HIDE;
-    }
-
     @Override
     public void dump(PrintWriter pw) {
-        pw.print(" DozeDockTriggers docking="); pw.println(isDocked());
+        pw.println("DozeDockHandler:");
+        pw.println(" dockState=" + mDockState);
     }
 
     private class DockEventListener implements DockManager.DockEventListener {
         private boolean mRegistered;
 
         @Override
-        public void onEvent(int event) {
-            if (DEBUG) Log.d(TAG, "dock event = " + event);
-            final DozeMachine.State dozeState = mMachine.getState();
-            mDockState = event;
+        public void onEvent(int dockState) {
+            if (DEBUG) Log.d(TAG, "dock event = " + dockState);
+            final DozeMachine.State nextState;
+            mDockState = dockState;
             switch (mDockState) {
                 case DockManager.STATE_DOCKED:
-                    requestPulse(dozeState);
+                    nextState = State.DOZE_AOD_DOCKED;
                     break;
                 case DockManager.STATE_NONE:
-                    if (dozeState == State.DOZE
-                            && mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
-                        mMachine.requestState(State.DOZE_AOD);
-                    }
-                    else {
-                        requestPulseOutNow(dozeState);
-                    }
+                    nextState = mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT) ? State.DOZE_AOD
+                            : State.DOZE;
                     break;
                 case DockManager.STATE_DOCKED_HIDE:
-                    if (dozeState == State.DOZE_AOD) {
-                        mMachine.requestState(State.DOZE);
-                    } else {
-                        requestPulseOutNow(dozeState);
-                    }
+                    nextState = State.DOZE;
                     break;
                 default:
-                    // no-op
+                    return;
             }
+
+            mMachine.requestState(nextState);
         }
 
         void register() {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 71e1593..43db85b 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -102,7 +102,7 @@
                 wrappedService, mDozeParameters);
 
         DozeMachine machine = new DozeMachine(wrappedService, config, wakeLock,
-                                              mWakefulnessLifecycle, mBatteryController, mDozeLog);
+                mWakefulnessLifecycle, mBatteryController, mDozeLog, mDockManager);
         machine.setParts(new DozeMachine.Part[]{
                 new DozePauser(mHandler, machine, mAlarmManager, mDozeParameters.getPolicy()),
                 new DozeFalsingManagerAdapter(mFalsingManager),
@@ -117,8 +117,7 @@
                         mDozeServiceHost, mDozeParameters, mHandler),
                 new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
                         mDozeParameters),
-                new DozeDockHandler(dozeService, machine, mDozeServiceHost, config, mHandler,
-                        mDockManager),
+                new DozeDockHandler(config, machine, mDockManager),
                 new DozeAuthRemover(dozeService)
         });
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 75b1d6c..40603ab 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -24,6 +24,7 @@
 import android.view.Display;
 
 import com.android.internal.util.Preconditions;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness;
 import com.android.systemui.statusbar.phone.DozeParameters;
@@ -72,7 +73,9 @@
         /** AOD, but the display is temporarily off. */
         DOZE_AOD_PAUSED,
         /** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
-        DOZE_AOD_PAUSING;
+        DOZE_AOD_PAUSING,
+        /** Always-on doze. Device is awake, showing docking UI and listening for pulse triggers. */
+        DOZE_AOD_DOCKED;
 
         boolean canPulse() {
             switch (this) {
@@ -80,6 +83,7 @@
                 case DOZE_AOD:
                 case DOZE_AOD_PAUSED:
                 case DOZE_AOD_PAUSING:
+                case DOZE_AOD_DOCKED:
                     return true;
                 default:
                     return false;
@@ -91,6 +95,7 @@
                 case DOZE_REQUEST_PULSE:
                 case DOZE_PULSING:
                 case DOZE_PULSING_BRIGHT:
+                case DOZE_AOD_DOCKED:
                     return true;
                 default:
                     return false;
@@ -109,6 +114,7 @@
                     return Display.STATE_OFF;
                 case DOZE_PULSING:
                 case DOZE_PULSING_BRIGHT:
+                case DOZE_AOD_DOCKED:
                     return Display.STATE_ON;
                 case DOZE_AOD:
                 case DOZE_AOD_PAUSING:
@@ -130,16 +136,18 @@
     private State mState = State.UNINITIALIZED;
     private int mPulseReason;
     private boolean mWakeLockHeldForCurrentState = false;
+    private DockManager mDockManager;
 
-    public DozeMachine(Service service, AmbientDisplayConfiguration config,
-            WakeLock wakeLock, WakefulnessLifecycle wakefulnessLifecycle,
-            BatteryController batteryController, DozeLog dozeLog) {
+    public DozeMachine(Service service, AmbientDisplayConfiguration config, WakeLock wakeLock,
+            WakefulnessLifecycle wakefulnessLifecycle, BatteryController batteryController,
+            DozeLog dozeLog, DockManager dockManager) {
         mDozeService = service;
         mConfig = config;
         mWakefulnessLifecycle = wakefulnessLifecycle;
         mWakeLock = wakeLock;
         mBatteryController = batteryController;
         mDozeLog = dozeLog;
+        mDockManager = dockManager;
     }
 
     /** Initializes the set of {@link Part}s. Must be called exactly once after construction. */
@@ -352,6 +360,8 @@
                 if (wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE
                         || wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING) {
                     nextState = State.FINISH;
+                } else if (mDockManager.isDocked()) {
+                    nextState = mDockManager.isHidden() ? State.DOZE : State.DOZE_AOD_DOCKED;
                 } else if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)) {
                     nextState = State.DOZE_AOD;
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index 39a2562..c9faf69 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -113,6 +113,7 @@
                 break;
             case DOZE_AOD:
             case DOZE_REQUEST_PULSE:
+            case DOZE_AOD_DOCKED:
                 setLightSensorEnabled(true);
                 break;
             case DOZE:
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index e1b4f31..3abeea9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
@@ -89,10 +90,10 @@
         }
 
         final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
-        final boolean pulseEnding = oldState  == DOZE_PULSE_DONE && newState == DOZE_AOD;
-        final boolean turningOn = (oldState == DOZE_AOD_PAUSED
-                || oldState  == DOZE) && newState == DOZE_AOD;
-        final boolean turningOff = (oldState == DOZE_AOD && newState == DOZE)
+        final boolean pulseEnding = oldState == DOZE_PULSE_DONE && isAlwaysOnState(newState);
+        final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE)
+                && isAlwaysOnState(newState);
+        final boolean turningOff = (isAlwaysOnState(oldState) && newState == DOZE)
                 || (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED);
         final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
         if (messagePending || justInitialized || pulseEnding || turningOn) {
@@ -131,6 +132,10 @@
         }
     }
 
+    private boolean isAlwaysOnState(DozeMachine.State state) {
+        return state == DOZE_AOD || state == DOZE_AOD_DOCKED;
+    }
+
     private void applyPendingScreenState() {
         applyScreenState(mPendingScreenState);
         mPendingScreenState = Display.STATE_UNKNOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 1134268..2d6b946 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -304,9 +304,7 @@
             case INITIALIZED:
                 mBroadcastReceiver.register(mBroadcastDispatcher);
                 mDozeHost.addCallback(mHostCallback);
-                if (mDockManager != null) {
-                    mDockManager.addListener(mDockEventListener);
-                }
+                mDockManager.addListener(mDockEventListener);
                 mDozeSensors.requestTemporaryDisable();
                 checkTriggersAtInit();
                 break;
@@ -326,6 +324,7 @@
                 break;
             case DOZE_PULSING:
             case DOZE_PULSING_BRIGHT:
+            case DOZE_AOD_DOCKED:
                 mDozeSensors.setTouchscreenSensorsListening(false);
                 mDozeSensors.setProxListening(true);
                 mDozeSensors.setPaused(false);
@@ -339,9 +338,7 @@
             case FINISH:
                 mBroadcastReceiver.unregister(mBroadcastDispatcher);
                 mDozeHost.removeCallback(mHostCallback);
-                if (mDockManager != null) {
-                    mDockManager.removeListener(mDockEventListener);
-                }
+                mDockManager.removeListener(mDockEventListener);
                 mDozeSensors.setListening(false);
                 mDozeSensors.setProxListening(false);
                 break;
@@ -399,7 +396,8 @@
 
     private boolean canPulse() {
         return mMachine.getState() == DozeMachine.State.DOZE
-                || mMachine.getState() == DozeMachine.State.DOZE_AOD;
+                || mMachine.getState() == DozeMachine.State.DOZE_AOD
+                || mMachine.getState() == DozeMachine.State.DOZE_AOD_DOCKED;
     }
 
     private void continuePulseRequest(int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index f155783..a6aa909 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -121,6 +121,7 @@
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
             case DOZE_AOD:
+            case DOZE_AOD_DOCKED:
                 if (oldState == DOZE_AOD_PAUSED || oldState == DOZE) {
                     // Whenever turning on the display, it's necessary to push a new frame.
                     // The display buffers will be empty and need to be filled.
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index 9457dc9..7f1b356 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -54,6 +54,7 @@
         switch (newState) {
             case DOZE:
             case DOZE_AOD:
+            case DOZE_AOD_DOCKED:
             case DOZE_AOD_PAUSING:
             case DOZE_AOD_PAUSED:
             case DOZE_REQUEST_PULSE:
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index bb2d142..51c2ddca 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -52,6 +52,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.sysprop.TelephonyProperties;
 import android.telecom.TelecomManager;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -81,7 +82,6 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.util.ScreenRecordHelper;
 import com.android.internal.util.ScreenshotHelper;
@@ -310,8 +310,7 @@
                 R.string.global_actions_airplane_mode_off_status) {
 
             void onToggle(boolean on) {
-                if (mHasTelephony && Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
                     mIsWaitingForEcmExit = true;
                     // Launch ECM exit dialog
                     Intent ecmDialogIntent =
@@ -328,8 +327,7 @@
                 if (!mHasTelephony) return;
 
                 // In ECM mode airplane state cannot be changed
-                if (!(Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                if (!TelephonyProperties.in_ecm_mode().orElse(false)) {
                     mState = buttonOn ? State.TurningOn : State.TurningOff;
                     mAirplaneState = mState;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 9f4056f..cb83656 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -36,9 +36,7 @@
 import com.android.systemui.SystemUIApplication;
 
 import javax.inject.Inject;
-import javax.inject.Singleton;
 
-@Singleton
 public class KeyguardService extends Service {
     static final String TAG = "KeyguardService";
     static final String PERMISSION = android.Manifest.permission.CONTROL_KEYGUARD;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index c876fa6..f026e68 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -18,9 +18,6 @@
 
 import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
 
-import static com.android.internal.telephony.IccCardConstants.State.ABSENT;
-import static com.android.internal.telephony.IccCardConstants.State.PIN_REQUIRED;
-import static com.android.internal.telephony.IccCardConstants.State.PUK_REQUIRED;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
@@ -61,7 +58,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
-import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManagerPolicyConstants;
@@ -72,7 +69,6 @@
 import com.android.internal.policy.IKeyguardDrawnCallback;
 import com.android.internal.policy.IKeyguardExitCallback;
 import com.android.internal.policy.IKeyguardStateCallback;
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardConstants;
@@ -293,7 +289,7 @@
      * Last SIM state reported by the telephony system.
      * Index is the slotId - in case of multiple SIM cards.
      */
-    private final SparseArray<IccCardConstants.State> mLastSimStates = new SparseArray<>();
+    private final SparseIntArray mLastSimStates = new SparseIntArray();
 
     private boolean mDeviceInteractive;
     private boolean mGoingToSleep;
@@ -433,7 +429,7 @@
         }
 
         @Override
-        public void onSimStateChanged(int subId, int slotId, IccCardConstants.State simState) {
+        public void onSimStateChanged(int subId, int slotId, int simState) {
 
             if (DEBUG_SIM_STATES) {
                 Log.d(TAG, "onSimStateChanged(subId=" + subId + ", slotId=" + slotId
@@ -455,14 +451,15 @@
 
             boolean simWasLocked;
             synchronized (KeyguardViewMediator.this) {
-                IccCardConstants.State lastState = mLastSimStates.get(slotId);
-                simWasLocked = (lastState == PIN_REQUIRED || lastState == PUK_REQUIRED);
+                int lastState = mLastSimStates.get(slotId);
+                simWasLocked = (lastState == TelephonyManager.SIM_STATE_PIN_REQUIRED
+                        || lastState == TelephonyManager.SIM_STATE_PUK_REQUIRED);
                 mLastSimStates.append(slotId, simState);
             }
 
             switch (simState) {
-                case NOT_READY:
-                case ABSENT:
+                case TelephonyManager.SIM_STATE_NOT_READY:
+                case TelephonyManager.SIM_STATE_ABSENT:
                     // only force lock screen in case of missing sim if user hasn't
                     // gone through setup wizard
                     synchronized (KeyguardViewMediator.this) {
@@ -476,7 +473,7 @@
                                 resetStateLocked();
                             }
                         }
-                        if (simState == ABSENT) {
+                        if (simState == TelephonyManager.SIM_STATE_ABSENT) {
                             // MVNO SIMs can become transiently NOT_READY when switching networks,
                             // so we should only lock when they are ABSENT.
                             if (simWasLocked) {
@@ -487,8 +484,8 @@
                         }
                     }
                     break;
-                case PIN_REQUIRED:
-                case PUK_REQUIRED:
+                case TelephonyManager.SIM_STATE_PIN_REQUIRED:
+                case TelephonyManager.SIM_STATE_PUK_REQUIRED:
                     synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
                             if (DEBUG_SIM_STATES) Log.d(TAG,
@@ -500,7 +497,7 @@
                         }
                     }
                     break;
-                case PERM_DISABLED:
+                case TelephonyManager.SIM_STATE_PERM_DISABLED:
                     synchronized (KeyguardViewMediator.this) {
                         if (!mShowing) {
                             if (DEBUG_SIM_STATES) Log.d(TAG, "PERM_DISABLED and "
@@ -513,7 +510,7 @@
                         }
                     }
                     break;
-                case READY:
+                case TelephonyManager.SIM_STATE_READY:
                     synchronized (KeyguardViewMediator.this) {
                         if (DEBUG_SIM_STATES) Log.d(TAG, "READY, reset state? " + mShowing);
                         if (mShowing && simWasLocked) {
@@ -1334,9 +1331,9 @@
             // if the setup wizard hasn't run yet, don't show
             final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim", false);
             final boolean absent = SubscriptionManager.isValidSubscriptionId(
-                    mUpdateMonitor.getNextSubIdForState(ABSENT));
+                    mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_ABSENT));
             final boolean disabled = SubscriptionManager.isValidSubscriptionId(
-                    mUpdateMonitor.getNextSubIdForState(IccCardConstants.State.PERM_DISABLED));
+                    mUpdateMonitor.getNextSubIdForState(TelephonyManager.SIM_STATE_PERM_DISABLED));
             final boolean lockedOrMissing = mUpdateMonitor.isSimPinSecure()
                     || ((absent || disabled) && requireSim);
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index c452f64..81e8a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -102,6 +102,7 @@
     private static final float DISABLED_ACTION_ALPHA = 0.54f;
 
     private int mMenuState;
+    private boolean mResize = true;
     private boolean mAllowMenuTimeout = true;
     private boolean mAllowTouches = true;
 
@@ -323,7 +324,7 @@
             if (mMenuContainerAnimator != null) {
                 mMenuContainerAnimator.cancel();
             }
-            notifyMenuStateChange(menuState);
+            notifyMenuStateChange(menuState, resizeMenuOnShow);
             mMenuContainerAnimator = new AnimatorSet();
             ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                     mMenuContainer.getAlpha(), 1f);
@@ -370,7 +371,7 @@
         if (mMenuState != MENU_STATE_NONE) {
             cancelDelayedFinish();
             if (notifyMenuVisibility) {
-                notifyMenuStateChange(MENU_STATE_NONE);
+                notifyMenuStateChange(MENU_STATE_NONE, mResize);
             }
             mMenuContainerAnimator = new AnimatorSet();
             ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
@@ -528,11 +529,13 @@
         mBackgroundDrawable.setAlpha(alpha);
     }
 
-    private void notifyMenuStateChange(int menuState) {
+    private void notifyMenuStateChange(int menuState, boolean resize) {
         mMenuState = menuState;
+        mResize = resize;
         Message m = Message.obtain();
         m.what = PipMenuActivityController.MESSAGE_MENU_STATE_CHANGED;
         m.arg1 = menuState;
+        m.arg2 = resize ?  1 : 0;
         sendMessage(m, "Could not notify controller of PIP menu visibility");
     }
 
@@ -571,6 +574,7 @@
         Message m = Message.obtain();
         m.what = PipMenuActivityController.MESSAGE_UPDATE_ACTIVITY_CALLBACK;
         m.replyTo = callback;
+        m.arg1 = mResize ?  1 : 0;
         sendMessage(m, "Could not notify controller of activity finished");
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index b8e0b81..f9b18cf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -138,7 +138,8 @@
             switch (msg.what) {
                 case MESSAGE_MENU_STATE_CHANGED: {
                     int menuState = msg.arg1;
-                    onMenuStateChanged(menuState, true /* resize */);
+                    boolean resize = msg.arg2 != 0;
+                    onMenuStateChanged(menuState, resize);
                     break;
                 }
                 case MESSAGE_EXPAND_PIP: {
@@ -166,7 +167,8 @@
                     }
                     // Mark the menu as invisible once the activity finishes as well
                     if (mToActivityMessenger == null) {
-                        onMenuStateChanged(MENU_STATE_NONE, true /* resize */);
+                        final boolean resize = msg.arg1 != 0;
+                        onMenuStateChanged(MENU_STATE_NONE, resize);
                     }
                     break;
                 }
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/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 6d434b1..c01bc8fe 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -33,7 +33,6 @@
 import com.android.systemui.DumpController;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.BgLooper;
 import com.android.systemui.dagger.qualifiers.MainHandler;
@@ -60,6 +59,7 @@
 import java.util.Collection;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Optional;
 import java.util.function.Predicate;
 
 import javax.inject.Inject;
@@ -88,7 +88,7 @@
     private final StatusBarIconController mIconController;
     private final ArrayList<QSFactory> mQsFactories = new ArrayList<>();
     private int mCurrentUser;
-    private StatusBar mStatusBar;
+    private final Optional<StatusBar> mStatusBarOptional;
 
     private QSColorController mQSColorController = QSColorController.Companion.getInstance();
 
@@ -102,7 +102,8 @@
             TunerService tunerService,
             Provider<AutoTileManager> autoTiles,
             DumpController dumpController,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            Optional<StatusBar> statusBarOptional) {
         mIconController = iconController;
         mContext = context;
         mTunerService = tunerService;
@@ -111,6 +112,7 @@
         mBroadcastDispatcher = broadcastDispatcher;
 
         mServices = new TileServices(this, bgLooper, mBroadcastDispatcher);
+        mStatusBarOptional = statusBarOptional;
 
         defaultFactory.setHost(this);
         mQsFactories.add(defaultFactory);
@@ -185,26 +187,17 @@
 
     @Override
     public void collapsePanels() {
-        if (mStatusBar == null) {
-            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        }
-        mStatusBar.postAnimateCollapsePanels();
+        mStatusBarOptional.ifPresent(StatusBar::postAnimateCollapsePanels);
     }
 
     @Override
     public void forceCollapsePanels() {
-        if (mStatusBar == null) {
-            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        }
-        mStatusBar.postAnimateForceCollapsePanels();
+        mStatusBarOptional.ifPresent(StatusBar::postAnimateForceCollapsePanels);
     }
 
     @Override
     public void openPanels() {
-        if (mStatusBar == null) {
-            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        }
-        mStatusBar.postAnimateOpenPanels();
+        mStatusBarOptional.ifPresent(StatusBar::postAnimateOpenPanels);
     }
 
     @Override
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/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index da74663..4afcf01 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -21,17 +21,16 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
-import android.os.SystemProperties;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.quicksettings.Tile;
+import android.sysprop.TelephonyProperties;
 import android.widget.Switch;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.plugins.ActivityStarter;
@@ -75,8 +74,7 @@
     public void handleClick() {
         boolean airplaneModeEnabled = mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !airplaneModeEnabled);
-        if (!airplaneModeEnabled && Boolean.parseBoolean(
-                SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+        if (!airplaneModeEnabled && TelephonyProperties.in_ecm_mode().orElse(false)) {
             mActivityStarter.postStartActivityDismissingKeyguard(
                     new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0);
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index 60bc6b6..fcdd234 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -35,7 +35,6 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
@@ -73,7 +72,7 @@
     }
 
     @Override
-    public void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {
+    public void onStart(Context context) {
         mContext = context;
         mHandler = new Handler();
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index ba9fc3d..ae48db2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -56,7 +56,6 @@
 
 import com.android.internal.policy.ScreenDecorationsUtils;
 import com.android.systemui.Dumpable;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.pip.PipUI;
 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
@@ -85,6 +84,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Class to send information from overview to launcher with a binder.
  */
@@ -103,6 +104,7 @@
 
     private final Context mContext;
     private final PipUI mPipUI;
+    private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
     private final Optional<Divider> mDividerOptional;
     private SysUiState mSysUiState;
     private final Handler mHandler;
@@ -139,11 +141,9 @@
             long token = Binder.clearCallingIdentity();
             try {
                 mHandler.post(() -> {
-                    StatusBar statusBar = SysUiServiceProvider.getComponent(mContext,
-                            StatusBar.class);
-                    if (statusBar != null) {
-                        statusBar.showScreenPinningRequest(taskId, false /* allowCancel */);
-                    }
+                    mStatusBarOptionalLazy.ifPresent(
+                            statusBarLazy -> statusBarLazy.get().showScreenPinningRequest(taskId,
+                                    false /* allowCancel */));
                 });
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -178,25 +178,25 @@
             long token = Binder.clearCallingIdentity();
             try {
                 // TODO move this logic to message queue
-                mHandler.post(()->{
-                    StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-                    if (bar != null) {
-
+                mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
+                    mHandler.post(()-> {
+                        StatusBar statusBar = statusBarLazy.get();
                         int action = event.getActionMasked();
                         if (action == ACTION_DOWN) {
                             mInputFocusTransferStarted = true;
                             mInputFocusTransferStartY = event.getY();
                             mInputFocusTransferStartMillis = event.getEventTime();
-                            bar.onInputFocusTransfer(mInputFocusTransferStarted, 0 /* velocity */);
+                            statusBar.onInputFocusTransfer(
+                                    mInputFocusTransferStarted, 0 /* velocity */);
                         }
                         if (action == ACTION_UP || action == ACTION_CANCEL) {
                             mInputFocusTransferStarted = false;
-                            bar.onInputFocusTransfer(mInputFocusTransferStarted,
+                            statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
                                     (event.getY() - mInputFocusTransferStartY)
                                     / (event.getEventTime() - mInputFocusTransferStartMillis));
                         }
                         event.recycle();
-                    }
+                    });
                 });
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -477,9 +477,10 @@
     public OverviewProxyService(Context context, DeviceProvisionedController provisionController,
             NavigationBarController navBarController, NavigationModeController navModeController,
             StatusBarWindowController statusBarWinController, SysUiState sysUiState, PipUI pipUI,
-            Optional<Divider> dividerOptional) {
+            Optional<Divider> dividerOptional, Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
         mContext = context;
         mPipUI = pipUI;
+        mStatusBarOptionalLazy = statusBarOptionalLazy;
         mHandler = new Handler();
         mNavBarController = navBarController;
         mStatusBarWinController = statusBarWinController;
@@ -594,11 +595,10 @@
     public void cleanupAfterDeath() {
         if (mInputFocusTransferStarted) {
             mHandler.post(()-> {
-                StatusBar bar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-                if (bar != null) {
+                mStatusBarOptionalLazy.ifPresent(statusBarLazy -> {
                     mInputFocusTransferStarted = false;
-                    bar.onInputFocusTransfer(false, 0 /* velocity */);
-                }
+                    statusBarLazy.get().onInputFocusTransfer(false, 0 /* velocity */);
+                });
             });
         }
         startConnectionToCurrentUser();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 882930b..5f37cc45 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -45,7 +45,7 @@
     @Override
     public void start() {
         mCommandQueue.addCallback(this);
-        mImpl.onStart(mContext, this);
+        mImpl.onStart(mContext);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
index 8cd17e9..1d29ac6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImplementation.java
@@ -19,15 +19,13 @@
 import android.content.res.Configuration;
 import android.graphics.Rect;
 
-import com.android.systemui.SysUiServiceProvider;
-
 import java.io.PrintWriter;
 
 /**
  * API for creating a Recents view.
  */
 public interface RecentsImplementation {
-    default void onStart(Context context, SysUiServiceProvider sysUiServiceProvider) {}
+    default void onStart(Context context) {}
     default void onBootCompleted() {}
     default void onAppTransitionFinished() {}
     default void onConfigurationChanged(Configuration newConfig) {}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 2d1c087..d819b8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -46,7 +46,6 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.WindowManagerWrapper;
@@ -56,11 +55,17 @@
 import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.ArrayList;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import dagger.Lazy;
 
 public class ScreenPinningRequest implements View.OnClickListener,
         NavigationModeController.ModeChangedListener {
 
     private final Context mContext;
+    private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
 
     private final AccessibilityManager mAccessibilityService;
     private final WindowManager mWindowManager;
@@ -72,8 +77,10 @@
     // Id of task to be pinned or locked.
     private int taskId;
 
-    public ScreenPinningRequest(Context context) {
+    @Inject
+    public ScreenPinningRequest(Context context, Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
         mContext = context;
+        mStatusBarOptionalLazy = statusBarOptionalLazy;
         mAccessibilityService = (AccessibilityManager)
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mWindowManager = (WindowManager)
@@ -254,9 +261,8 @@
                         .setVisibility(View.INVISIBLE);
             }
 
-            StatusBar statusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-            NavigationBarView navigationBarView =
-                    statusBar != null ? statusBar.getNavigationBarView() : null;
+            NavigationBarView navigationBarView = mStatusBarOptionalLazy.map(
+                    statusBarLazy -> statusBarLazy.get().getNavigationBarView()).orElse(null);
             final boolean recentsVisible = navigationBarView != null
                     && navigationBarView.isRecentsButtonVisible();
             boolean touchExplorationEnabled = mAccessibilityService.isTouchExplorationEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java
new file mode 100644
index 0000000..8c48655
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteImageInBackgroundTask.java
@@ -0,0 +1,43 @@
+/*
+ * 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.screenshot;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+/**
+ * An AsyncTask that deletes an image from the media store in the background.
+ */
+class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> {
+    private Context mContext;
+
+    DeleteImageInBackgroundTask(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    protected Void doInBackground(Uri... params) {
+        if (params.length != 1) return null;
+
+        Uri screenshotUri = params[0];
+        ContentResolver resolver = mContext.getContentResolver();
+        resolver.delete(screenshotUri, null, null);
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 3ff6d0d..7963203 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -32,49 +32,31 @@
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
 import android.app.Notification;
-import android.app.Notification.BigPictureStyle;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
-import android.content.ClipData;
-import android.content.ClipDescription;
 import android.content.ComponentName;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics.Picture;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.media.MediaActionSound;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
-import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.DeviceConfig;
-import android.provider.MediaStore;
-import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
@@ -90,25 +72,15 @@
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIFactory;
 import com.android.systemui.dagger.qualifiers.MainResources;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.util.NotificationChannels;
 
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
 import java.util.Collections;
-import java.util.Date;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.CompletableFuture;
@@ -131,7 +103,7 @@
     /**
      * POD used in the AsyncTask which saves an image in the background.
      */
-    private static class SaveImageInBackgroundData {
+    static class SaveImageInBackgroundData {
         public Context context;
         public Bitmap image;
         public Uri imageUri;
@@ -147,396 +119,12 @@
             imageUri = null;
             iconSize = 0;
         }
+
         void clearContext() {
             context = null;
         }
     }
 
-    /**
-     * An AsyncTask that saves an image to the media store in the background.
-     */
-    private static class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
-        private static final String TAG = "SaveImageInBackgroundTask";
-
-        private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
-        private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
-
-        private final SaveImageInBackgroundData mParams;
-        private final NotificationManager mNotificationManager;
-        private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
-        private final String mImageFileName;
-        private final long mImageTime;
-        private final BigPictureStyle mNotificationStyle;
-        private final int mImageWidth;
-        private final int mImageHeight;
-        private final Handler mHandler;
-        private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
-
-        SaveImageInBackgroundTask(Context context, SaveImageInBackgroundData data,
-                NotificationManager nManager) {
-            Resources r = context.getResources();
-
-            // Prepare all the output metadata
-            mParams = data;
-            mImageTime = System.currentTimeMillis();
-            String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
-            mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
-
-            // Initialize screenshot notification smart actions provider.
-            mHandler = new Handler();
-            mSmartActionsProvider =
-                SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider();
-
-            // Create the large notification icon
-            mImageWidth = data.image.getWidth();
-            mImageHeight = data.image.getHeight();
-            int iconSize = data.iconSize;
-            int previewWidth = data.previewWidth;
-            int previewHeight = data.previewheight;
-
-            Paint paint = new Paint();
-            ColorMatrix desat = new ColorMatrix();
-            desat.setSaturation(0.25f);
-            paint.setColorFilter(new ColorMatrixColorFilter(desat));
-            Matrix matrix = new Matrix();
-            int overlayColor = 0x40FFFFFF;
-
-            matrix.setTranslate((previewWidth - mImageWidth) / 2,
-                    (previewHeight - mImageHeight) / 2);
-            Bitmap picture = generateAdjustedHwBitmap(data.image, previewWidth, previewHeight,
-                    matrix, paint, overlayColor);
-
-            // Note, we can't use the preview for the small icon, since it is non-square
-            float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight);
-            matrix.setScale(scale, scale);
-            matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
-                    (iconSize - (scale * mImageHeight)) / 2);
-            Bitmap icon = generateAdjustedHwBitmap(data.image, iconSize, iconSize, matrix, paint,
-                    overlayColor);
-
-            mNotificationManager = nManager;
-            final long now = System.currentTimeMillis();
-
-            // Setup the notification
-            mNotificationStyle = new Notification.BigPictureStyle()
-                    .bigPicture(picture.createAshmemBitmap());
-
-            // The public notification will show similar info but with the actual screenshot omitted
-            mPublicNotificationBuilder =
-                    new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP)
-                            .setContentTitle(r.getString(R.string.screenshot_saving_title))
-                            .setSmallIcon(R.drawable.stat_notify_image)
-                            .setCategory(Notification.CATEGORY_PROGRESS)
-                            .setWhen(now)
-                            .setShowWhen(true)
-                            .setColor(r.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color));
-            SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder, true);
-
-            mNotificationBuilder = new Notification.Builder(context,
-                    NotificationChannels.SCREENSHOTS_HEADSUP)
-                    .setContentTitle(r.getString(R.string.screenshot_saving_title))
-                    .setSmallIcon(R.drawable.stat_notify_image)
-                    .setWhen(now)
-                    .setShowWhen(true)
-                    .setColor(r.getColor(
-                            com.android.internal.R.color.system_notification_accent_color))
-                    .setStyle(mNotificationStyle)
-                    .setPublicVersion(mPublicNotificationBuilder.build());
-            mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
-            SystemUI.overrideNotificationAppName(context, mNotificationBuilder, true);
-
-            mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
-                    mNotificationBuilder.build());
-
-            /**
-             * NOTE: The following code prepares the notification builder for updating the
-             * notification after the screenshot has been written to disk.
-             */
-
-            // On the tablet, the large icon makes the notification appear as if it is clickable
-            // (and on small devices, the large icon is not shown) so defer showing the large icon
-            // until we compose the final post-save notification below.
-            mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap());
-            // But we still don't set it for the expanded view, allowing the smallIcon to show here.
-            mNotificationStyle.bigLargeIcon((Bitmap) null);
-        }
-
-        private int getUserHandleOfForegroundApplication(Context context) {
-            // This logic matches
-            // com.android.systemui.statusbar.phone.PhoneStatusBarPolicy#updateManagedProfile
-            try {
-                return ActivityTaskManager.getService().getLastResumedActivityUserId();
-            } catch (RemoteException e) {
-                Slog.w(TAG, "getUserHandleOfForegroundApplication: ", e);
-                return context.getUserId();
-            }
-        }
-
-        private boolean isManagedProfile(Context context) {
-            UserManager manager = UserManager.get(context);
-            UserInfo info = manager.getUserInfo(getUserHandleOfForegroundApplication(context));
-            return info.isManagedProfile();
-        }
-
-        /**
-         * Generates a new hardware bitmap with specified values, copying the content from the
-         * passed in bitmap.
-         */
-        private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix,
-                Paint paint, int color) {
-            Picture picture = new Picture();
-            Canvas canvas = picture.beginRecording(width, height);
-            canvas.drawColor(color);
-            canvas.drawBitmap(bitmap, matrix, paint);
-            picture.endRecording();
-            return Bitmap.createBitmap(picture);
-        }
-
-        @Override
-        protected Void doInBackground(Void... paramsUnused) {
-            if (isCancelled()) {
-                return null;
-            }
-
-            // By default, AsyncTask sets the worker thread to have background thread priority,
-            // so bump it back up so that we save a little quicker.
-            Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
-
-            Context context = mParams.context;
-            Bitmap image = mParams.image;
-            boolean smartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
-                    SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
-            CompletableFuture<List<Notification.Action>> smartActionsFuture = getSmartActionsFuture(
-                    context, image, mSmartActionsProvider, mHandler, smartActionsEnabled,
-                    isManagedProfile(context));
-
-            Resources r = context.getResources();
-
-            try {
-                // Save the screenshot to the MediaStore
-                final MediaStore.PendingParams params = new MediaStore.PendingParams(
-                        MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png");
-                params.setRelativePath(Environment.DIRECTORY_PICTURES + File.separator
-                        + Environment.DIRECTORY_SCREENSHOTS);
-
-                final Uri uri = MediaStore.createPending(context, params);
-                final MediaStore.PendingSession session = MediaStore.openPending(context, uri);
-                try {
-                    try (OutputStream out = session.openOutputStream()) {
-                        if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
-                            throw new IOException("Failed to compress");
-                        }
-                    }
-                    session.publish();
-                } catch (Exception e) {
-                    session.abandon();
-                    throw e;
-                } finally {
-                    IoUtils.closeQuietly(session);
-                }
-
-                // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
-                // order to do some common work like dismissing the keyguard and sending
-                // closeSystemWindows
-
-                // Create a share intent, this will always go through the chooser activity first
-                // which should not trigger auto-enter PiP
-                String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
-                String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
-                Intent sharingIntent = new Intent(Intent.ACTION_SEND);
-                sharingIntent.setType("image/png");
-                sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
-                // Include URI in ClipData also, so that grantPermission picks it up.
-                // We don't use setData here because some apps interpret this as "to:".
-                ClipData clipdata = new ClipData(new ClipDescription("content",
-                        new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
-                        new ClipData.Item(uri));
-                sharingIntent.setClipData(clipdata);
-                sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
-                sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-                // Make sure pending intents for the system user are still unique across users
-                // by setting the (otherwise unused) request code to the current user id.
-                int requestCode = context.getUserId();
-
-                PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode,
-                        new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
-                        PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-                Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null,
-                        chooserAction.getIntentSender())
-                        .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
-                        .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-                // Create a share action for the notification
-                PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode,
-                        new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
-                                .putExtra(EXTRA_ACTION_INTENT, sharingChooserIntent)
-                                .putExtra(EXTRA_DISALLOW_ENTER_PIP, true)
-                                .setAction(Intent.ACTION_SEND),
-                        PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
-                Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
-                        R.drawable.ic_screenshot_share,
-                        r.getString(com.android.internal.R.string.share), shareAction);
-                mNotificationBuilder.addAction(shareActionBuilder.build());
-
-                // Create an edit intent, if a specific package is provided as the editor, then
-                // launch that directly
-                String editorPackage = context.getString(R.string.config_screenshotEditor);
-                Intent editIntent = new Intent(Intent.ACTION_EDIT);
-                if (!TextUtils.isEmpty(editorPackage)) {
-                    editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-                }
-                editIntent.setType("image/png");
-                editIntent.setData(uri);
-                editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-
-                // Create a edit action
-                PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
-                        new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
-                                .putExtra(EXTRA_ACTION_INTENT, editIntent)
-                                .putExtra(EXTRA_CANCEL_NOTIFICATION,
-                                        editIntent.getComponent() != null)
-                                .setAction(Intent.ACTION_EDIT),
-                        PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
-                Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
-                        R.drawable.ic_screenshot_edit,
-                        r.getString(com.android.internal.R.string.screenshot_edit), editAction);
-                mNotificationBuilder.addAction(editActionBuilder.build());
-                if (editAction != null && mParams.onEditReady != null) {
-                    mParams.onEditReady.apply(editAction);
-                }
-
-                // Create a delete action for the notification
-                PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode,
-                        new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
-                                .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
-                        PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
-                Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
-                        R.drawable.ic_screenshot_delete,
-                        r.getString(com.android.internal.R.string.delete), deleteAction);
-                mNotificationBuilder.addAction(deleteActionBuilder.build());
-
-                mParams.imageUri = uri;
-                mParams.image = null;
-                mParams.errorMsgResId = 0;
-
-                if (smartActionsEnabled) {
-                    int timeoutMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
-                            SystemUiDeviceConfigFlags
-                                    .SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS,
-                            1000);
-                    List<Notification.Action> smartActions = getSmartActions(smartActionsFuture,
-                            timeoutMs);
-                    for (Notification.Action action : smartActions) {
-                        mNotificationBuilder.addAction(action);
-                    }
-                }
-            } catch (Exception e) {
-                // IOException/UnsupportedOperationException may be thrown if external storage is
-                // not mounted
-                Slog.e(TAG, "unable to save screenshot", e);
-                mParams.clearImage();
-                mParams.errorMsgResId = R.string.screenshot_failed_to_save_text;
-            }
-
-            // Recycle the bitmap data
-            if (image != null) {
-                image.recycle();
-            }
-
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void params) {
-            if (mParams.errorMsgResId != 0) {
-                // Show a message that we've failed to save the image to disk
-                GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager,
-                        mParams.errorMsgResId);
-            } else {
-                if (mParams.onEditReady != null) {
-                    // Cancel the "saving screenshot" notification
-                    mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
-                } else {
-                    // Show the final notification to indicate screenshot saved
-                    Context context = mParams.context;
-                    Resources r = context.getResources();
-
-                    // Create the intent to show the screenshot in gallery
-                    Intent launchIntent = new Intent(Intent.ACTION_VIEW);
-                    launchIntent.setDataAndType(mParams.imageUri, "image/png");
-                    launchIntent.setFlags(
-                            Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-                    final long now = System.currentTimeMillis();
-
-                    // Update the text and the icon for the existing notification
-                    mPublicNotificationBuilder
-                            .setContentTitle(r.getString(R.string.screenshot_saved_title))
-                            .setContentText(r.getString(R.string.screenshot_saved_text))
-                            .setContentIntent(
-                                    PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
-                            .setWhen(now)
-                            .setAutoCancel(true)
-                            .setColor(context.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color));
-                    mNotificationBuilder
-                            .setContentTitle(r.getString(R.string.screenshot_saved_title))
-                            .setContentText(r.getString(R.string.screenshot_saved_text))
-                            .setContentIntent(PendingIntent.getActivity(mParams.context, 0,
-                                    launchIntent, 0))
-                            .setWhen(now)
-                            .setAutoCancel(true)
-                            .setColor(context.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color))
-                            .setPublicVersion(mPublicNotificationBuilder.build())
-                            .setFlag(Notification.FLAG_NO_CLEAR, false);
-
-                    mNotificationManager.notify(SystemMessage.NOTE_GLOBAL_SCREENSHOT,
-                            mNotificationBuilder.build());
-                }
-            }
-            mParams.finisher.run();
-            mParams.clearContext();
-        }
-
-        @Override
-        protected void onCancelled(Void params) {
-            // If we are cancelled while the task is running in the background, we may get null
-            // params. The finisher is expected to always be called back, so just use the baked-in
-            // params from the ctor in any case.
-            mParams.finisher.run();
-            mParams.clearImage();
-            mParams.clearContext();
-
-            // Cancel the posted notification
-            mNotificationManager.cancel(SystemMessage.NOTE_GLOBAL_SCREENSHOT);
-        }
-    }
-
-    /**
-     * An AsyncTask that deletes an image from the media store in the background.
-     */
-    private static class DeleteImageInBackgroundTask extends AsyncTask<Uri, Void, Void> {
-        private Context mContext;
-
-        DeleteImageInBackgroundTask(Context context) {
-            mContext = context;
-        }
-
-        @Override
-        protected Void doInBackground(Uri... params) {
-            if (params.length != 1) return null;
-
-            Uri screenshotUri = params[0];
-            ContentResolver resolver = mContext.getContentResolver();
-            resolver.delete(screenshotUri, null, null);
-            return null;
-        }
-    }
-
     static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
     static final String EXTRA_ACTION_INTENT = "android:screenshot_action_intent";
     static final String EXTRA_CANCEL_NOTIFICATION = "android:screenshot_cancel_notification";
@@ -600,7 +188,6 @@
         }
     };
 
-
     /**
      * @param context everything needs a context :(
      */
@@ -631,25 +218,25 @@
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
                 WindowManager.LayoutParams.TYPE_SCREENSHOT,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                    | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+                        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
                 PixelFormat.TRANSLUCENT);
         mWindowLayoutParams.setTitle("ScreenshotAnimation");
         mWindowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
         mNotificationManager =
-            (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
+                (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
         mDisplay = mWindowManager.getDefaultDisplay();
         mDisplayMetrics = new DisplayMetrics();
         mDisplay.getRealMetrics(mDisplayMetrics);
 
         // Get the various target sizes
         mNotificationIconSize =
-            resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
+                resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height);
 
         // Scale has to account for both sides of the bg
         mBgPadding = (float) resources.getDimensionPixelSize(R.dimen.global_screenshot_bg_padding);
-        mBgPaddingScale = mBgPadding /  mDisplayMetrics.widthPixels;
+        mBgPaddingScale = mBgPadding / mDisplayMetrics.widthPixels;
 
         // determine the optimal preview size
         int panelWidth = 0;
@@ -877,6 +464,7 @@
             mScreenshotAnimation.start();
         });
     }
+
     private ValueAnimator createScreenshotDropInAnimation() {
         final float flashPeakDurationPct = ((float) (SCREENSHOT_FLASH_TO_PEAK_DURATION)
                 / SCREENSHOT_DROP_IN_DURATION);
@@ -926,6 +514,7 @@
                 mScreenshotFlash.setAlpha(0f);
                 mScreenshotFlash.setVisibility(View.VISIBLE);
             }
+
             @Override
             public void onAnimationEnd(android.animation.Animator animation) {
                 mScreenshotFlash.setVisibility(View.GONE);
@@ -936,7 +525,7 @@
             public void onAnimationUpdate(ValueAnimator animation) {
                 float t = (Float) animation.getAnimatedValue();
                 float scaleT = (SCREENSHOT_SCALE + mBgPaddingScale)
-                    - scaleInterpolator.getInterpolation(t)
+                        - scaleInterpolator.getInterpolation(t)
                         * (SCREENSHOT_SCALE - SCREENSHOT_DROP_IN_MIN_SCALE);
                 mBackgroundView.setAlpha(scaleInterpolator.getInterpolation(t) * BACKGROUND_ALPHA);
                 mScreenshotView.setAlpha(t);
@@ -947,6 +536,7 @@
         });
         return anim;
     }
+
     private ValueAnimator createScreenshotDropOutAnimation(int w, int h, boolean statusBarVisible,
             boolean navBarVisible) {
         ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
@@ -968,7 +558,8 @@
                 public void onAnimationUpdate(ValueAnimator animation) {
                     float t = (Float) animation.getAnimatedValue();
                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
+                            - t * (SCREENSHOT_DROP_IN_MIN_SCALE
+                            - SCREENSHOT_FAST_DROP_OUT_MIN_SCALE);
                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
                     mScreenshotView.setAlpha(1f - t);
                     mScreenshotView.setScaleX(scaleT);
@@ -995,8 +586,10 @@
             float halfScreenHeight = (h - 2f * mBgPadding) / 2f;
             final float offsetPct = SCREENSHOT_DROP_OUT_MIN_SCALE_OFFSET;
             final PointF finalPos = new PointF(
-                -halfScreenWidth + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
-                -halfScreenHeight + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
+                    -halfScreenWidth
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenWidth,
+                    -halfScreenHeight
+                            + (SCREENSHOT_DROP_OUT_MIN_SCALE + offsetPct) * halfScreenHeight);
 
             // Animate the screenshot to the status bar
             anim.setDuration(SCREENSHOT_DROP_OUT_DURATION);
@@ -1005,7 +598,7 @@
                 public void onAnimationUpdate(ValueAnimator animation) {
                     float t = (Float) animation.getAnimatedValue();
                     float scaleT = (SCREENSHOT_DROP_IN_MIN_SCALE + mBgPaddingScale)
-                        - scaleInterpolator.getInterpolation(t)
+                            - scaleInterpolator.getInterpolation(t)
                             * (SCREENSHOT_DROP_IN_MIN_SCALE - SCREENSHOT_DROP_OUT_MIN_SCALE);
                     mBackgroundView.setAlpha((1f - t) * BACKGROUND_ALPHA);
                     mScreenshotView.setAlpha(1f - scaleInterpolator.getInterpolation(t));
@@ -1066,15 +659,15 @@
 
         // Repurpose the existing notification to notify the user of the error
         Notification.Builder b = new Notification.Builder(context, NotificationChannels.ALERTS)
-            .setTicker(r.getString(R.string.screenshot_failed_title))
-            .setContentTitle(r.getString(R.string.screenshot_failed_title))
-            .setContentText(errorMsg)
-            .setSmallIcon(R.drawable.stat_notify_image_error)
-            .setWhen(System.currentTimeMillis())
-            .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
-            .setCategory(Notification.CATEGORY_ERROR)
-            .setAutoCancel(true)
-            .setColor(context.getColor(
+                .setTicker(r.getString(R.string.screenshot_failed_title))
+                .setContentTitle(r.getString(R.string.screenshot_failed_title))
+                .setContentText(errorMsg)
+                .setSmallIcon(R.drawable.stat_notify_image_error)
+                .setWhen(System.currentTimeMillis())
+                .setVisibility(Notification.VISIBILITY_PUBLIC) // ok to show outside lockscreen
+                .setCategory(Notification.CATEGORY_ERROR)
+                .setAutoCancel(true)
+                .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
new file mode 100644
index 0000000..083f971
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -0,0 +1,472 @@
+/*
+ * 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.screenshot;
+
+import android.app.ActivityTaskManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Picture;
+import android.media.ExifInterface;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIFactory;
+import com.android.systemui.util.NotificationChannels;
+
+import libcore.io.IoUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * An AsyncTask that saves an image to the media store in the background.
+ */
+class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> {
+    private static final String TAG = "SaveImageInBackgroundTask";
+
+    private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
+    private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
+
+    private final GlobalScreenshot.SaveImageInBackgroundData mParams;
+    private final NotificationManager mNotificationManager;
+    private final Notification.Builder mNotificationBuilder, mPublicNotificationBuilder;
+    private final String mImageFileName;
+    private final long mImageTime;
+    private final Notification.BigPictureStyle mNotificationStyle;
+    private final int mImageWidth;
+    private final int mImageHeight;
+    private final Handler mHandler;
+    private final ScreenshotNotificationSmartActionsProvider mSmartActionsProvider;
+
+    SaveImageInBackgroundTask(Context context, GlobalScreenshot.SaveImageInBackgroundData data,
+            NotificationManager nManager) {
+        Resources r = context.getResources();
+
+        // Prepare all the output metadata
+        mParams = data;
+        mImageTime = System.currentTimeMillis();
+        String imageDate = new SimpleDateFormat("yyyyMMdd-HHmmss").format(new Date(mImageTime));
+        mImageFileName = String.format(SCREENSHOT_FILE_NAME_TEMPLATE, imageDate);
+
+        // Initialize screenshot notification smart actions provider.
+        mHandler = new Handler();
+        mSmartActionsProvider =
+                SystemUIFactory.getInstance().createScreenshotNotificationSmartActionsProvider();
+
+        // Create the large notification icon
+        mImageWidth = data.image.getWidth();
+        mImageHeight = data.image.getHeight();
+        int iconSize = data.iconSize;
+        int previewWidth = data.previewWidth;
+        int previewHeight = data.previewheight;
+
+        Paint paint = new Paint();
+        ColorMatrix desat = new ColorMatrix();
+        desat.setSaturation(0.25f);
+        paint.setColorFilter(new ColorMatrixColorFilter(desat));
+        Matrix matrix = new Matrix();
+        int overlayColor = 0x40FFFFFF;
+
+        matrix.setTranslate((previewWidth - mImageWidth) / 2,
+                (previewHeight - mImageHeight) / 2);
+        Bitmap picture = generateAdjustedHwBitmap(data.image, previewWidth, previewHeight,
+                matrix, paint, overlayColor);
+
+        // Note, we can't use the preview for the small icon, since it is non-square
+        float scale = (float) iconSize / Math.min(mImageWidth, mImageHeight);
+        matrix.setScale(scale, scale);
+        matrix.postTranslate((iconSize - (scale * mImageWidth)) / 2,
+                (iconSize - (scale * mImageHeight)) / 2);
+        Bitmap icon = generateAdjustedHwBitmap(data.image, iconSize, iconSize, matrix, paint,
+                overlayColor);
+
+        mNotificationManager = nManager;
+        final long now = System.currentTimeMillis();
+
+        // Setup the notification
+        mNotificationStyle = new Notification.BigPictureStyle()
+                .bigPicture(picture.createAshmemBitmap());
+
+        // The public notification will show similar info but with the actual screenshot omitted
+        mPublicNotificationBuilder =
+                new Notification.Builder(context, NotificationChannels.SCREENSHOTS_HEADSUP)
+                        .setContentTitle(r.getString(R.string.screenshot_saving_title))
+                        .setSmallIcon(R.drawable.stat_notify_image)
+                        .setCategory(Notification.CATEGORY_PROGRESS)
+                        .setWhen(now)
+                        .setShowWhen(true)
+                        .setColor(r.getColor(
+                                com.android.internal.R.color.system_notification_accent_color));
+        SystemUI.overrideNotificationAppName(context, mPublicNotificationBuilder, true);
+
+        mNotificationBuilder = new Notification.Builder(context,
+                NotificationChannels.SCREENSHOTS_HEADSUP)
+                .setContentTitle(r.getString(R.string.screenshot_saving_title))
+                .setSmallIcon(R.drawable.stat_notify_image)
+                .setWhen(now)
+                .setShowWhen(true)
+                .setColor(r.getColor(
+                        com.android.internal.R.color.system_notification_accent_color))
+                .setStyle(mNotificationStyle)
+                .setPublicVersion(mPublicNotificationBuilder.build());
+        mNotificationBuilder.setFlag(Notification.FLAG_NO_CLEAR, true);
+        SystemUI.overrideNotificationAppName(context, mNotificationBuilder, true);
+
+        mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+                mNotificationBuilder.build());
+
+        /**
+         * NOTE: The following code prepares the notification builder for updating the
+         * notification after the screenshot has been written to disk.
+         */
+
+        // On the tablet, the large icon makes the notification appear as if it is clickable
+        // (and on small devices, the large icon is not shown) so defer showing the large icon
+        // until we compose the final post-save notification below.
+        mNotificationBuilder.setLargeIcon(icon.createAshmemBitmap());
+        // But we still don't set it for the expanded view, allowing the smallIcon to show here.
+        mNotificationStyle.bigLargeIcon((Bitmap) null);
+    }
+
+    private int getUserHandleOfForegroundApplication(Context context) {
+        // This logic matches
+        // com.android.systemui.statusbar.phone.PhoneStatusBarPolicy#updateManagedProfile
+        try {
+            return ActivityTaskManager.getService().getLastResumedActivityUserId();
+        } catch (RemoteException e) {
+            Slog.w(TAG, "getUserHandleOfForegroundApplication: ", e);
+            return context.getUserId();
+        }
+    }
+
+    private boolean isManagedProfile(Context context) {
+        UserManager manager = UserManager.get(context);
+        UserInfo info = manager.getUserInfo(getUserHandleOfForegroundApplication(context));
+        return info.isManagedProfile();
+    }
+
+    /**
+     * Generates a new hardware bitmap with specified values, copying the content from the
+     * passed in bitmap.
+     */
+    private Bitmap generateAdjustedHwBitmap(Bitmap bitmap, int width, int height, Matrix matrix,
+            Paint paint, int color) {
+        Picture picture = new Picture();
+        Canvas canvas = picture.beginRecording(width, height);
+        canvas.drawColor(color);
+        canvas.drawBitmap(bitmap, matrix, paint);
+        picture.endRecording();
+        return Bitmap.createBitmap(picture);
+    }
+
+    @Override
+    protected Void doInBackground(Void... paramsUnused) {
+        if (isCancelled()) {
+            return null;
+        }
+
+        // By default, AsyncTask sets the worker thread to have background thread priority,
+        // so bump it back up so that we save a little quicker.
+        Process.setThreadPriority(Process.THREAD_PRIORITY_FOREGROUND);
+
+        Context context = mParams.context;
+        Bitmap image = mParams.image;
+        boolean smartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
+        CompletableFuture<List<Notification.Action>>
+                smartActionsFuture = GlobalScreenshot.getSmartActionsFuture(
+                context, image, mSmartActionsProvider, mHandler, smartActionsEnabled,
+                isManagedProfile(context));
+
+        Resources r = context.getResources();
+
+        try {
+            // Save the screenshot to the MediaStore
+            final MediaStore.PendingParams params = new MediaStore.PendingParams(
+                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mImageFileName, "image/png");
+            params.setRelativePath(Environment.DIRECTORY_PICTURES + File.separator
+                    + Environment.DIRECTORY_SCREENSHOTS);
+
+            final Uri uri = MediaStore.createPending(context, params);
+            final MediaStore.PendingSession session = MediaStore.openPending(context, uri);
+            try {
+                // First, write the actual data for our screenshot
+                try (OutputStream out = session.openOutputStream()) {
+                    if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
+                        throw new IOException("Failed to compress");
+                    }
+                }
+
+                // Next, write metadata to help index the screenshot
+                try (ParcelFileDescriptor pfd = session.open()) {
+                    final ExifInterface exif = new ExifInterface(pfd.getFileDescriptor());
+
+                    exif.setAttribute(ExifInterface.TAG_SOFTWARE,
+                            "Android " + Build.DISPLAY);
+
+                    exif.setAttribute(ExifInterface.TAG_IMAGE_WIDTH,
+                            Integer.toString(image.getWidth()));
+                    exif.setAttribute(ExifInterface.TAG_IMAGE_LENGTH,
+                            Integer.toString(image.getHeight()));
+
+                    final ZonedDateTime time = ZonedDateTime.ofInstant(
+                            Instant.ofEpochMilli(mImageTime), ZoneId.systemDefault());
+                    exif.setAttribute(ExifInterface.TAG_DATETIME_ORIGINAL,
+                            DateTimeFormatter.ofPattern("yyyy:MM:dd HH:mm:ss").format(time));
+                    exif.setAttribute(ExifInterface.TAG_SUBSEC_TIME_ORIGINAL,
+                            DateTimeFormatter.ofPattern("SSS").format(time));
+
+                    if (Objects.equals(time.getOffset(), ZoneOffset.UTC)) {
+                        exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL, "+00:00");
+                    } else {
+                        exif.setAttribute(ExifInterface.TAG_OFFSET_TIME_ORIGINAL,
+                                DateTimeFormatter.ofPattern("XXX").format(time));
+                    }
+
+                    exif.saveAttributes();
+                }
+                session.publish();
+            } catch (Exception e) {
+                session.abandon();
+                throw e;
+            } finally {
+                IoUtils.closeQuietly(session);
+            }
+
+            // Note: Both the share and edit actions are proxied through ActionProxyReceiver in
+            // order to do some common work like dismissing the keyguard and sending
+            // closeSystemWindows
+
+            // Create a share intent, this will always go through the chooser activity first
+            // which should not trigger auto-enter PiP
+            String subjectDate = DateFormat.getDateTimeInstance().format(new Date(mImageTime));
+            String subject = String.format(SCREENSHOT_SHARE_SUBJECT_TEMPLATE, subjectDate);
+            Intent sharingIntent = new Intent(Intent.ACTION_SEND);
+            sharingIntent.setType("image/png");
+            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
+            // Include URI in ClipData also, so that grantPermission picks it up.
+            // We don't use setData here because some apps interpret this as "to:".
+            ClipData clipdata = new ClipData(new ClipDescription("content",
+                    new String[]{ClipDescription.MIMETYPE_TEXT_PLAIN}),
+                    new ClipData.Item(uri));
+            sharingIntent.setClipData(clipdata);
+            sharingIntent.putExtra(Intent.EXTRA_SUBJECT, subject);
+            sharingIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+            // Make sure pending intents for the system user are still unique across users
+            // by setting the (otherwise unused) request code to the current user id.
+            int requestCode = context.getUserId();
+
+            PendingIntent chooserAction = PendingIntent.getBroadcast(context, requestCode,
+                    new Intent(context, GlobalScreenshot.TargetChosenReceiver.class),
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+            Intent sharingChooserIntent = Intent.createChooser(sharingIntent, null,
+                    chooserAction.getIntentSender())
+                    .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
+                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+            // Create a share action for the notification
+            PendingIntent shareAction = PendingIntent.getBroadcastAsUser(context, requestCode,
+                    new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+                            .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, sharingChooserIntent)
+                            .putExtra(GlobalScreenshot.EXTRA_DISALLOW_ENTER_PIP, true)
+                            .setAction(Intent.ACTION_SEND),
+                    PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
+            Notification.Action.Builder shareActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_share,
+                    r.getString(com.android.internal.R.string.share), shareAction);
+            mNotificationBuilder.addAction(shareActionBuilder.build());
+
+            // Create an edit intent, if a specific package is provided as the editor, then
+            // launch that directly
+            String editorPackage = context.getString(R.string.config_screenshotEditor);
+            Intent editIntent = new Intent(Intent.ACTION_EDIT);
+            if (!TextUtils.isEmpty(editorPackage)) {
+                editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+            }
+            editIntent.setType("image/png");
+            editIntent.setData(uri);
+            editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+            editIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+            // Create a edit action
+            PendingIntent editAction = PendingIntent.getBroadcastAsUser(context, requestCode,
+                    new Intent(context, GlobalScreenshot.ActionProxyReceiver.class)
+                            .putExtra(GlobalScreenshot.EXTRA_ACTION_INTENT, editIntent)
+                            .putExtra(GlobalScreenshot.EXTRA_CANCEL_NOTIFICATION,
+                                    editIntent.getComponent() != null)
+                            .setAction(Intent.ACTION_EDIT),
+                    PendingIntent.FLAG_CANCEL_CURRENT, UserHandle.SYSTEM);
+            Notification.Action.Builder editActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_edit,
+                    r.getString(com.android.internal.R.string.screenshot_edit), editAction);
+            mNotificationBuilder.addAction(editActionBuilder.build());
+            if (editAction != null && mParams.onEditReady != null) {
+                mParams.onEditReady.apply(editAction);
+            }
+
+            // Create a delete action for the notification
+            PendingIntent deleteAction = PendingIntent.getBroadcast(context, requestCode,
+                    new Intent(context, GlobalScreenshot.DeleteScreenshotReceiver.class)
+                            .putExtra(GlobalScreenshot.SCREENSHOT_URI_ID, uri.toString()),
+                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT);
+            Notification.Action.Builder deleteActionBuilder = new Notification.Action.Builder(
+                    R.drawable.ic_screenshot_delete,
+                    r.getString(com.android.internal.R.string.delete), deleteAction);
+            mNotificationBuilder.addAction(deleteActionBuilder.build());
+
+            mParams.imageUri = uri;
+            mParams.image = null;
+            mParams.errorMsgResId = 0;
+
+            if (smartActionsEnabled) {
+                int timeoutMs = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
+                        SystemUiDeviceConfigFlags
+                                .SCREENSHOT_NOTIFICATION_SMART_ACTIONS_TIMEOUT_MS,
+                        1000);
+                List<Notification.Action> smartActions = GlobalScreenshot.getSmartActions(
+                        smartActionsFuture,
+                        timeoutMs);
+                for (Notification.Action action : smartActions) {
+                    mNotificationBuilder.addAction(action);
+                }
+            }
+        } catch (Exception e) {
+            // IOException/UnsupportedOperationException may be thrown if external storage is
+            // not mounted
+            Slog.e(TAG, "unable to save screenshot", e);
+            mParams.clearImage();
+            mParams.errorMsgResId = R.string.screenshot_failed_to_save_text;
+        }
+
+        // Recycle the bitmap data
+        if (image != null) {
+            image.recycle();
+        }
+
+        return null;
+    }
+
+    @Override
+    protected void onPostExecute(Void params) {
+        if (mParams.errorMsgResId != 0) {
+            // Show a message that we've failed to save the image to disk
+            GlobalScreenshot.notifyScreenshotError(mParams.context, mNotificationManager,
+                    mParams.errorMsgResId);
+        } else {
+            if (mParams.onEditReady != null) {
+                // Cancel the "saving screenshot" notification
+                mNotificationManager.cancel(
+                        SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+            } else {
+                // Show the final notification to indicate screenshot saved
+                Context context = mParams.context;
+                Resources r = context.getResources();
+
+                // Create the intent to show the screenshot in gallery
+                Intent launchIntent = new Intent(Intent.ACTION_VIEW);
+                launchIntent.setDataAndType(mParams.imageUri, "image/png");
+                launchIntent.setFlags(
+                        Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+                final long now = System.currentTimeMillis();
+
+                // Update the text and the icon for the existing notification
+                mPublicNotificationBuilder
+                        .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                        .setContentText(r.getString(R.string.screenshot_saved_text))
+                        .setContentIntent(
+                                PendingIntent.getActivity(mParams.context, 0, launchIntent, 0))
+                        .setWhen(now)
+                        .setAutoCancel(true)
+                        .setColor(context.getColor(
+                                com.android.internal.R.color.system_notification_accent_color));
+                mNotificationBuilder
+                        .setContentTitle(r.getString(R.string.screenshot_saved_title))
+                        .setContentText(r.getString(R.string.screenshot_saved_text))
+                        .setContentIntent(PendingIntent.getActivity(mParams.context, 0,
+                                launchIntent, 0))
+                        .setWhen(now)
+                        .setAutoCancel(true)
+                        .setColor(context.getColor(
+                                com.android.internal.R.color.system_notification_accent_color))
+                        .setPublicVersion(mPublicNotificationBuilder.build())
+                        .setFlag(Notification.FLAG_NO_CLEAR, false);
+
+                mNotificationManager.notify(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT,
+                        mNotificationBuilder.build());
+            }
+        }
+        mParams.finisher.run();
+        mParams.clearContext();
+    }
+
+    @Override
+    protected void onCancelled(Void params) {
+        // If we are cancelled while the task is running in the background, we may get null
+        // params. The finisher is expected to always be called back, so just use the baked-in
+        // params from the ctor in any case.
+        mParams.finisher.run();
+        mParams.clearImage();
+        mParams.clearContext();
+
+        // Cancel the posted notification
+        mNotificationManager.cancel(SystemMessageProto.SystemMessage.NOTE_GLOBAL_SCREENSHOT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 20d24e6..fd63506 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -28,9 +28,7 @@
 import android.view.WindowManager;
 
 import javax.inject.Inject;
-import javax.inject.Singleton;
 
-@Singleton
 public class TakeScreenshotService extends Service {
     private static final String TAG = "TakeScreenshotService";
 
diff --git a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
index a571f01..5ae0954 100644
--- a/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/shortcut/ShortcutKeyDispatcher.java
@@ -46,6 +46,7 @@
 
     private static final String TAG = "ShortcutKeyDispatcher";
     private final Divider mDivider;
+    private final Recents mRecents;
 
     private ShortcutKeyServiceProxy mShortcutKeyServiceProxy = new ShortcutKeyServiceProxy(this);
     private IWindowManager mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -59,9 +60,10 @@
     protected final long SC_DOCK_RIGHT = META_MASK | KeyEvent.KEYCODE_RIGHT_BRACKET;
 
     @Inject
-    public ShortcutKeyDispatcher(Context context, Divider divider) {
+    public ShortcutKeyDispatcher(Context context, Divider divider, Recents recents) {
         super(context);
         mDivider = divider;
+        mRecents = recents;
     }
 
     /**
@@ -96,8 +98,7 @@
             int dockSide = mWindowManagerService.getDockedStackSide();
             if (dockSide == WindowManager.DOCKED_INVALID) {
                 // Split the screen
-                Recents recents = getComponent(Recents.class);
-                recents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
+                mRecents.splitPrimaryTask((shortcutCode == SC_DOCK_LEFT)
                         ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
                         : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT, null, -1);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index d12f3ee..90cc0e57 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -34,12 +34,16 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.Optional;
+
+import dagger.Lazy;
 
 /**
  * Controls the docked stack divider.
  */
 public class Divider extends SystemUI implements DividerView.DividerCallbacks {
     private static final String TAG = "Divider";
+    private final Optional<Lazy<Recents>> mRecentsOptionalLazy;
 
     private DividerWindowManager mWindowManager;
     private DividerView mView;
@@ -51,8 +55,9 @@
     private boolean mHomeStackResizable = false;
     private ForcedResizableInfoActivityController mForcedResizableController;
 
-    public Divider(Context context) {
+    public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy) {
         super(context);
+        mRecentsOptionalLazy = recentsOptionalLazy;
     }
 
     @Override
@@ -216,10 +221,7 @@
 
     @Override
     public void growRecents() {
-        Recents recents = getComponent(Recents.class);
-        if (recents != null) {
-            recents.growRecents();
-        }
+        mRecentsOptionalLazy.ifPresent(recentsLazy -> recentsLazy.get().growRecents());
     }
 
     @Override
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/NotificationListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
index c4de2d3..98a2675 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationListener.java
@@ -110,8 +110,7 @@
                 }
 
                 String key = sbn.getKey();
-                boolean isUpdate =
-                        mEntryManager.getNotificationData().get(key) != null;
+                boolean isUpdate = mEntryManager.getActiveNotificationUnfiltered(key) != null;
                 // In case we don't allow child notifications, we ignore children of
                 // notifications that have a summary, since` we're not going to show them
                 // anyway. This is true also when the summary is canceled,
@@ -126,8 +125,7 @@
                     if (isUpdate) {
                         mEntryManager.removeNotification(key, rankingMap, UNDEFINED_DISMISS_REASON);
                     } else {
-                        mEntryManager.getNotificationData()
-                                .updateRanking(rankingMap, "onNotificationPosted");
+                        mEntryManager.updateRanking(rankingMap, "onNotificationPosted");
                     }
                     return;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 571d3d7..021e7e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -15,6 +15,7 @@
  */
 package com.android.systemui.statusbar;
 
+import static android.app.Notification.VISIBILITY_SECRET;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED;
 
 import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -126,7 +127,7 @@
                 updatePublicMode();
                 // The filtering needs to happen before the update call below in order to make sure
                 // the presenter has the updated notifications from the new user
-                getEntryManager().getNotificationData().filterAndSort("user switched");
+                getEntryManager().reapplyFilterAndSort("user switched");
                 mPresenter.onUserSwitched(mCurrentUserId);
 
                 for (UserChangedListener listener : mListeners) {
@@ -148,17 +149,17 @@
                     }
                 }
                 if (notificationKey != null) {
-                    final int count =
-                            getEntryManager().getNotificationData().getActiveNotifications().size();
-                    final int rank = getEntryManager().getNotificationData().getRank(notificationKey);
+                    NotificationEntry entry =
+                            getEntryManager().getActiveNotificationUnfiltered(notificationKey);
+                    final int count = getEntryManager().getActiveNotificationsCount();
+                    final int rank = entry != null ? entry.getRanking().getRank() : 0;
                     NotificationVisibility.NotificationLocation location =
-                            NotificationLogger.getNotificationLocation(
-                                    getEntryManager().getNotificationData().get(notificationKey));
+                            NotificationLogger.getNotificationLocation(entry);
                     final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
                             rank, count, true, location);
                     try {
                         mBarService.onNotificationClick(notificationKey, nv);
-                    } catch (RemoteException e) {
+                    } catch (RemoteException exception) {
                         /* ignore */
                     }
                 }
@@ -311,9 +312,9 @@
             Log.wtf(TAG, "mEntryManager was null!", new Throwable());
             return true;
         }
-        return isLockscreenPublicMode(mCurrentUserId)
-                && getEntryManager().getNotificationData().getVisibilityOverride(key) ==
-                        Notification.VISIBILITY_SECRET;
+        NotificationEntry visibleEntry = getEntryManager().getActiveNotificationUnfiltered(key);
+        return isLockscreenPublicMode(mCurrentUserId) && visibleEntry != null
+                && visibleEntry.getRanking().getVisibilityOverride() == VISIBILITY_SECRET;
     }
 
     public boolean shouldShowOnKeyguard(NotificationEntry entry) {
@@ -326,8 +327,7 @@
                 && hideSilentNotificationsOnLockscreen()) {
             exceedsPriorityThreshold = entry.getBucket() != BUCKET_SILENT;
         } else {
-            exceedsPriorityThreshold =
-                    !getEntryManager().getNotificationData().isAmbient(entry.getKey());
+            exceedsPriorityThreshold = !entry.getRanking().isAmbient();
         }
         return mShowLockscreenNotifications && exceedsPriorityThreshold;
     }
@@ -467,8 +467,9 @@
             Log.wtf(TAG, "mEntryManager was null!", new Throwable());
             return true;
         }
-        return getEntryManager().getNotificationData().getVisibilityOverride(key) ==
-                Notification.VISIBILITY_PRIVATE;
+        NotificationEntry entry = getEntryManager().getActiveNotificationUnfiltered(key);
+        return entry != null
+                && entry.getRanking().getVisibilityOverride() == Notification.VISIBILITY_PRIVATE;
     }
 
     private void updateCurrentProfilesCache() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index d668665..a98f826 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -102,8 +102,7 @@
     }
 
 
-    // Late binding
-    private NotificationEntryManager mEntryManager;
+    private final NotificationEntryManager mEntryManager;
 
     // Late binding, also @Nullable due to being in com.android.systemui.statusbar.phone package
     @Nullable
@@ -258,8 +257,9 @@
         if (mMediaNotificationKey == null) {
             return null;
         }
-        synchronized (mEntryManager.getNotificationData()) {
-            NotificationEntry entry = mEntryManager.getNotificationData().get(mMediaNotificationKey);
+        synchronized (mEntryManager) {
+            NotificationEntry entry = mEntryManager
+                    .getActiveNotificationUnfiltered(mMediaNotificationKey);
             if (entry == null || entry.expandedIcon == null) {
                 return null;
             }
@@ -281,8 +281,9 @@
     public void findAndUpdateMediaNotifications() {
         boolean metaDataChanged = false;
 
-        synchronized (mEntryManager.getNotificationData()) {
-            Set<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
+        synchronized (mEntryManager) {
+            Set<NotificationEntry> allNotifications =
+                    mEntryManager.getPendingAndActiveNotifications();
 
             // Promote the media notification with a controller in 'playing' state, if any.
             NotificationEntry mediaNotification = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 35f06f9..e10d27b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -184,8 +184,9 @@
                 ViewGroup actionGroup = (ViewGroup) parent;
                 buttonIndex = actionGroup.indexOfChild(view);
             }
-            final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
-            final int rank = mEntryManager.getNotificationData().getRank(key);
+            final int count = mEntryManager.getActiveNotificationsCount();
+            final int rank = mEntryManager
+                    .getActiveNotificationUnfiltered(key).getRanking().getRank();
 
             // Notification may be updated before this function is executed, and thus play safe
             // here and verify that the action object is still the one that where the click happens.
@@ -202,7 +203,7 @@
             }
             NotificationVisibility.NotificationLocation location =
                     NotificationLogger.getNotificationLocation(
-                            mEntryManager.getNotificationData().get(key));
+                            mEntryManager.getActiveNotificationUnfiltered(key));
             final NotificationVisibility nv =
                     NotificationVisibility.obtain(key, rank, count, true, location);
             try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 20a3e35..ef733a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -140,8 +140,7 @@
         Assert.isMainThread();
         beginUpdate();
 
-        ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
-                .getActiveNotifications();
+        List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
         ArrayList<ExpandableNotificationRow> toShow = new ArrayList<>(activeNotifications.size());
         final int N = activeNotifications.size();
         for (int i = 0; i < N; i++) {
@@ -339,7 +338,7 @@
                 }
                 for (ExpandableNotificationRow remove : toRemove) {
                     parent.removeChildNotification(remove);
-                    if (mEntryManager.getNotificationData().get(
+                    if (mEntryManager.getActiveNotificationUnfiltered(
                             remove.getStatusBarNotification().getKey()) == null) {
                         // We only want to add an animation if the view is completely removed
                         // otherwise it's just a transfer
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
index 843c37f..0a7ee3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/OperatorNameView.java
@@ -20,11 +20,11 @@
 import android.os.Bundle;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import com.android.internal.telephony.IccCardConstants.State;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.settingslib.WirelessUtils;
@@ -138,9 +138,9 @@
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
             int subId = subs.get(i).getSubscriptionId();
-            State simState = mKeyguardUpdateMonitor.getSimState(subId);
+            int simState = mKeyguardUpdateMonitor.getSimState(subId);
             CharSequence carrierName = subs.get(i).getCarrierName();
-            if (!TextUtils.isEmpty(carrierName) && simState == State.READY) {
+            if (!TextUtils.isEmpty(carrierName) && simState == TelephonyManager.SIM_STATE_READY) {
                 ServiceState ss = mKeyguardUpdateMonitor.getServiceState(subId);
                 if (ss != null && ss.getState() == ServiceState.STATE_IN_SERVICE) {
                     displayText = carrierName;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
index 7bdb21d..40f8e39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SmartReplyController.java
@@ -73,8 +73,8 @@
     public void smartActionClicked(
             NotificationEntry entry, int actionIndex, Notification.Action action,
             boolean generatedByAssistant) {
-        final int count = mEntryManager.getNotificationData().getActiveNotifications().size();
-        final int rank = mEntryManager.getNotificationData().getRank(entry.getKey());
+        final int count = mEntryManager.getActiveNotificationsCount();
+        final int rank = entry.getRanking().getRank();
         NotificationVisibility.NotificationLocation location =
                 NotificationLogger.getNotificationLocation(entry);
         final NotificationVisibility nv = NotificationVisibility.obtain(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index f4af9ae..dc84b57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -185,6 +185,16 @@
         maybeUpdateIconScaleDimens();
     }
 
+    public StatusBarIconView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mDozer = new NotificationIconDozeHelper(context);
+        mBlocked = false;
+        mAlwaysScaleIcon = true;
+        reloadDimens();
+        maybeUpdateIconScaleDimens();
+        mDensity = context.getResources().getDisplayMetrics().densityDpi;
+    }
+
     /** Should always be preceded by {@link #reloadDimens()} */
     private void maybeUpdateIconScaleDimens() {
         // We do not resize and scale system icons (on the right), only notification icons (on the
@@ -277,16 +287,6 @@
         maybeUpdateIconScaleDimens();
     }
 
-    public StatusBarIconView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mDozer = new NotificationIconDozeHelper(context);
-        mBlocked = false;
-        mAlwaysScaleIcon = true;
-        reloadDimens();
-        maybeUpdateIconScaleDimens();
-        mDensity = context.getResources().getDisplayMetrics().densityDpi;
-    }
-
     private static boolean streq(String a, String b) {
         if (a == b) {
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 689d161..239addd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -208,11 +208,9 @@
 
     @Override
     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
-        if (!isInArea(area, this)) {
-            return;
-        }
+        float intensity = isInArea(area, this) ? darkIntensity : 0;
         mMobileDrawable.setTintList(
-                ColorStateList.valueOf(mDualToneHandler.getSingleColor(darkIntensity)));
+                ColorStateList.valueOf(mDualToneHandler.getSingleColor(intensity)));
         ColorStateList color = ColorStateList.valueOf(getTint(area, this, tint));
         mIn.setImageTintList(color);
         mOut.setImageTintList(color);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 23e2d27..6dbcc44 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -236,15 +236,13 @@
 
     @Override
     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
-        if (!isInArea(area, this)) {
-            return;
-        }
-
-        mWifiIcon.setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
-        mIn.setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
-        mOut.setImageTintList(ColorStateList.valueOf(getTint(area, this, tint)));
-        mDotView.setDecorColor(tint);
-        mDotView.setIconColor(tint, false);
+        int areaTint = getTint(area, this, tint);
+        ColorStateList color = ColorStateList.valueOf(areaTint);
+        mWifiIcon.setImageTintList(color);
+        mIn.setImageTintList(color);
+        mOut.setImageTintList(color);
+        mDotView.setDecorColor(areaTint);
+        mDotView.setIconColor(areaTint, false);
     }
 
 
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/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 314dc04..015c323 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -37,14 +37,14 @@
  */
 @Singleton
 class BypassHeadsUpNotifier @Inject constructor(
-        private val context: Context,
-        private val bypassController: KeyguardBypassController,
-        private val statusBarStateController: StatusBarStateController,
-        private val headsUpManager: HeadsUpManagerPhone,
-        private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
-        private val mediaManager: NotificationMediaManager,
-        tunerService: TunerService) : StatusBarStateController.StateListener,
-        NotificationMediaManager.MediaListener {
+    private val context: Context,
+    private val bypassController: KeyguardBypassController,
+    private val statusBarStateController: StatusBarStateController,
+    private val headsUpManager: HeadsUpManagerPhone,
+    private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
+    private val mediaManager: NotificationMediaManager,
+    tunerService: TunerService
+) : StatusBarStateController.StateListener, NotificationMediaManager.MediaListener {
 
     private lateinit var entryManager: NotificationEntryManager
     private var currentMediaEntry: NotificationEntry? = null
@@ -77,7 +77,8 @@
 
     override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
         val previous = currentMediaEntry
-        var newEntry = entryManager.notificationData.get(mediaManager.mediaNotificationKey)
+        var newEntry = entryManager
+                .getActiveNotificationUnfiltered(mediaManager.mediaNotificationKey)
         if (!NotificationMediaManager.isPlayingState(state)) {
             newEntry = null
         }
@@ -101,7 +102,7 @@
      */
     private fun canAutoHeadsUp(entry: NotificationEntry): Boolean {
         if (!isAutoHeadsUpAllowed()) {
-            return false;
+            return false
         }
         if (entry.isSensitive) {
             // filter sensitive notifications
@@ -111,7 +112,7 @@
             // filter notifications invisible on Keyguard
             return false
         }
-        if (!entryManager.notificationData.activeNotifications.contains(entry)) {
+        if (entryManager.getActiveNotificationUnfiltered(entry.key) != null) {
             // filter notifications not the active list currently
             return false
         }
@@ -125,7 +126,7 @@
     /**
      * @return {@code true} if autoHeadsUp is possible right now.
      */
-    private fun isAutoHeadsUpAllowed() : Boolean {
+    private fun isAutoHeadsUpAllowed(): Boolean {
         if (!enabled) {
             return false
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NewNotifPipeline.java
deleted file mode 100644
index 31921a4..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NewNotifPipeline.java
+++ /dev/null
@@ -1,49 +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.systemui.statusbar.notification;
-
-import android.util.Log;
-
-import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * Initialization code for the new notification pipeline.
- */
-@Singleton
-public class NewNotifPipeline {
-    private final NotifCollection mNotifCollection;
-
-    @Inject
-    public NewNotifPipeline(
-            NotifCollection notifCollection) {
-        mNotifCollection = notifCollection;
-    }
-
-    /** Hooks the new pipeline up to NotificationManager */
-    public void initialize(
-            NotificationListener notificationService) {
-        mNotifCollection.attach(notificationService);
-
-        Log.d(TAG, "Notif pipeline initialized");
-    }
-
-    private static final String TAG = "NewNotifPipeline";
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 005f01d..65f3fa9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -71,7 +71,7 @@
             }
 
             @Override
-            public void onPostEntryUpdated(NotificationEntry entry) {
+            public void onPreEntryUpdated(NotificationEntry entry) {
                 updateAlertState(entry);
             }
 
@@ -114,8 +114,8 @@
 
     private void updateAlertState(NotificationEntry entry) {
         boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification());
-        boolean shouldAlert;
-        shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
+        // includes check for whether this notification should be filtered:
+        boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
         final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey());
         if (wasAlerting) {
             if (shouldAlert) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index df78fa3..0694920 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -99,7 +99,8 @@
     /**
      * Called whenever notification ranking changes, in response to
      * {@link NotificationListenerService#onNotificationRankingUpdate}. This is called after
-     * NotificationData has processed the update and notifications have been re-sorted and filtered.
+     * NotificationEntryManager has processed the update and notifications have been re-sorted
+     * and filtered.
      *
      * @param rankingMap provides access to ranking information on currently active notifications
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
index 13d90ff..7a58097 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryManager.java
@@ -18,10 +18,12 @@
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 import static android.service.notification.NotificationListenerService.REASON_ERROR;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Notification;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -36,9 +38,8 @@
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
 import com.android.systemui.statusbar.NotificationUiAdjustment;
 import com.android.systemui.statusbar.NotificationUpdateHandler;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.logging.NotifEvent;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
@@ -46,12 +47,15 @@
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.Assert;
 import com.android.systemui.util.leak.LeakDetector;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -62,9 +66,29 @@
 import javax.inject.Singleton;
 
 /**
- * NotificationEntryManager is responsible for the adding, removing, and updating of notifications.
- * It also handles tasks such as their inflation and their interaction with other
- * Notification.*Manager objects.
+ * NotificationEntryManager is responsible for the adding, removing, and updating of
+ * {@link NotificationEntry}s. It also handles tasks such as their inflation and their interaction
+ * with other Notification.*Manager objects.
+ *
+ * We track notification entries through this lifecycle:
+ *      1. Pending
+ *      2. Active
+ *      3. Sorted / filtered (visible)
+ *
+ * Every entry spends some amount of time in the pending state, while it is being inflated. Once
+ * inflated, an entry moves into the active state, where it _could_ potentially be shown to the
+ * user. After an entry makes its way into the active state, we sort and filter the entire set to
+ * repopulate the visible set.
+ *
+ * There are a few different things that other classes may be interested in, and most of them
+ * involve the current set of notifications. Here's a brief overview of things you may want to know:
+ * @see #getVisibleNotifications() for the visible set
+ * @see #getActiveNotificationUnfiltered(String) to check if a key exists
+ * @see #getPendingNotificationsIterator() for an iterator over the pending notifications
+ * @see #getPendingOrActiveNotif(String) to find a notification exists for that key in any list
+ * @see #getPendingAndActiveNotifications() to get the entire set of Notifications that we're
+ * aware of
+ * @see #getActiveNotificationsForCurrentUser() to see every notification that the current user owns
  */
 @Singleton
 public class NotificationEntryManager implements
@@ -78,12 +102,23 @@
     /**
      * Used when a notification is removed and it doesn't have a reason that maps to one of the
      * reasons defined in NotificationListenerService
-     * (e.g. {@link NotificationListenerService.REASON_CANCEL})
+     * (e.g. {@link NotificationListenerService#REASON_CANCEL})
      */
     public static final int UNDEFINED_DISMISS_REASON = 0;
 
+    /** Pending notifications are ones awaiting inflation */
     @VisibleForTesting
     protected final HashMap<String, NotificationEntry> mPendingNotifications = new HashMap<>();
+    /**
+     * Active notifications have been inflated / prepared and could become visible, but may get
+     * filtered out if for instance they are not for the current user
+     */
+    private final ArrayMap<String, NotificationEntry> mActiveNotifications = new ArrayMap<>();
+    @VisibleForTesting
+    /** This is the list of "active notifications for this user in this context" */
+    protected final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
+    private final List<NotificationEntry> mReadOnlyNotifications =
+            Collections.unmodifiableList(mSortedAndFiltered);
 
     private final Map<NotificationEntry, NotificationLifetimeExtender> mRetainedNotifications =
             new ArrayMap<>();
@@ -92,10 +127,12 @@
     private NotificationRemoteInputManager mRemoteInputManager;
     private NotificationRowBinder mNotificationRowBinder;
 
+    private final KeyguardEnvironment mKeyguardEnvironment;
+    private final NotificationGroupManager mGroupManager;
+    private final NotificationRankingManager mRankingManager;
+
     private NotificationPresenter mPresenter;
-    private NotificationListenerService.RankingMap mLatestRankingMap;
-    @VisibleForTesting
-    protected NotificationData mNotificationData;
+    private RankingMap mLatestRankingMap;
     private NotifLog mNotifLog;
 
     @VisibleForTesting
@@ -129,10 +166,14 @@
 
     @Inject
     public NotificationEntryManager(
-            NotificationData notificationData,
-            NotifLog notifLog) {
-        mNotificationData = notificationData;
+            NotifLog notifLog,
+            NotificationGroupManager groupManager,
+            NotificationRankingManager rankingManager,
+            KeyguardEnvironment keyguardEnvironment) {
         mNotifLog = notifLog;
+        mGroupManager = groupManager;
+        mRankingManager = rankingManager;
+        mKeyguardEnvironment = keyguardEnvironment;
     }
 
     /** Adds a {@link NotificationEntryListener}. */
@@ -171,7 +212,6 @@
             NotificationListContainer listContainer,
             HeadsUpManager headsUpManager) {
         mPresenter = presenter;
-        mNotificationData.setHeadsUpManager(headsUpManager);
     }
 
     /** Adds multiple {@link NotificationLifetimeExtender}s. */
@@ -188,10 +228,6 @@
                 UNDEFINED_DISMISS_REASON));
     }
 
-    public NotificationData getNotificationData() {
-        return mNotificationData;
-    }
-
     @Override
     public void onReorderingAllowed() {
         updateNotifications("reordering is now allowed");
@@ -212,10 +248,17 @@
     }
 
     private NotificationVisibility obtainVisibility(String key) {
-        final int rank = mNotificationData.getRank(key);
-        final int count = mNotificationData.getActiveNotifications().size();
+        NotificationEntry e = mActiveNotifications.get(key);
+        final int rank;
+        if (e != null) {
+            rank = e.getRanking().getRank();
+        } else {
+            rank = 0;
+        }
+
+        final int count = mActiveNotifications.size();
         NotificationVisibility.NotificationLocation location =
-                NotificationLogger.getNotificationLocation(getNotificationData().get(key));
+                NotificationLogger.getNotificationLocation(getActiveNotificationUnfiltered(key));
         return NotificationVisibility.obtain(key, rank, count, true, location);
     }
 
@@ -227,7 +270,7 @@
             mNotifLog.log(NotifEvent.INFLATION_ABORTED, entry.getSbn(), null,
                     "PendingNotification aborted. " + reason);
         }
-        NotificationEntry addedEntry = mNotificationData.get(key);
+        NotificationEntry addedEntry = getActiveNotificationUnfiltered(key);
         if (addedEntry != null) {
             addedEntry.abortTask();
             mNotifLog.log(NotifEvent.INFLATION_ABORTED, addedEntry.getSbn(),
@@ -258,13 +301,13 @@
         // If there was an async task started after the removal, we don't want to add it back to
         // the list, otherwise we might get leaks.
         if (!entry.isRowRemoved()) {
-            boolean isNew = mNotificationData.get(entry.getKey()) == null;
+            boolean isNew = getActiveNotificationUnfiltered(entry.getKey()) == null;
             if (isNew) {
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     mNotifLog.log(NotifEvent.INFLATED, entry);
                     listener.onEntryInflated(entry, inflatedFlags);
                 }
-                mNotificationData.add(entry);
+                addActiveNotification(entry);
                 updateNotifications("onAsyncInflationFinished");
                 for (NotificationEntryListener listener : mNotificationEntryListeners) {
                     listener.onNotificationAdded(entry);
@@ -278,8 +321,34 @@
         }
     }
 
+    /**
+     * Equivalent to the old NotificationData#add
+     * @param entry - an entry which is prepared for display
+     */
+    private void addActiveNotification(NotificationEntry entry) {
+        Assert.isMainThread();
+
+        mActiveNotifications.put(entry.getKey(), entry);
+        mGroupManager.onEntryAdded(entry);
+        updateRankingAndSort(mRankingManager.getRankingMap(), "addEntryInternalInternal");
+    }
+
+    /**
+     * Available so that tests can directly manipulate the list of active notifications easily
+     *
+     * @param entry the entry to add directly to the visible notification map
+     */
+    @VisibleForTesting
+    public void addActiveNotificationForTest(NotificationEntry entry) {
+        mActiveNotifications.put(entry.getKey(), entry);
+        mGroupManager.onEntryAdded(entry);
+
+        reapplyFilterAndSort("addVisibleNotification");
+    }
+
+
     @Override
-    public void removeNotification(String key, NotificationListenerService.RankingMap ranking,
+    public void removeNotification(String key, RankingMap ranking,
             int reason) {
         removeNotificationInternal(key, ranking, obtainVisibility(key), false /* forceRemove */,
                 false /* removedByUser */, reason);
@@ -287,7 +356,7 @@
 
     private void removeNotificationInternal(
             String key,
-            @Nullable NotificationListenerService.RankingMap ranking,
+            @Nullable RankingMap ranking,
             @Nullable NotificationVisibility visibility,
             boolean forceRemove,
             boolean removedByUser,
@@ -300,7 +369,7 @@
             return;
         }
 
-        final NotificationEntry entry = mNotificationData.get(key);
+        final NotificationEntry entry = getActiveNotificationUnfiltered(key);
         boolean lifetimeExtended = false;
 
         // Notification was canceled before it got inflated
@@ -355,8 +424,7 @@
 
                 // Let's remove the children if this was a summary
                 handleGroupSummaryRemoved(key);
-
-                mNotificationData.remove(key, ranking);
+                removeVisibleNotification(key);
                 updateNotifications("removeNotificationInternal");
                 Dependency.get(LeakDetector.class).trackGarbage(entry);
                 removedByUser |= entryDismissed;
@@ -381,7 +449,7 @@
      *
      */
     private void handleGroupSummaryRemoved(String key) {
-        NotificationEntry entry = mNotificationData.get(key);
+        NotificationEntry entry = getActiveNotificationUnfiltered(key);
         if (entry != null && entry.rowExists() && entry.isSummaryWithChildren()) {
             if (entry.getSbn().getOverrideGroupKey() != null && !entry.isRowDismissed()) {
                 // We don't want to remove children for autobundled notifications as they are not
@@ -413,13 +481,14 @@
     }
 
     private void addNotificationInternal(StatusBarNotification notification,
-            NotificationListenerService.RankingMap rankingMap) throws InflationException {
+            RankingMap rankingMap) throws InflationException {
         String key = notification.getKey();
         if (DEBUG) {
             Log.d(TAG, "addNotification key=" + key);
         }
 
-        mNotificationData.updateRanking(rankingMap, "addNotificationInternal");
+        updateRankingAndSort(rankingMap, "addNotificationInternal");
+
         Ranking ranking = new Ranking();
         rankingMap.getRanking(key, ranking);
 
@@ -439,8 +508,7 @@
     }
 
     @Override
-    public void addNotification(StatusBarNotification notification,
-            NotificationListenerService.RankingMap ranking) {
+    public void addNotification(StatusBarNotification notification, RankingMap ranking) {
         try {
             addNotificationInternal(notification, ranking);
         } catch (InflationException e) {
@@ -449,12 +517,12 @@
     }
 
     private void updateNotificationInternal(StatusBarNotification notification,
-            NotificationListenerService.RankingMap ranking) throws InflationException {
+            RankingMap ranking) throws InflationException {
         if (DEBUG) Log.d(TAG, "updateNotification(" + notification + ")");
 
         final String key = notification.getKey();
         abortExistingInflation(key, "updateNotification");
-        NotificationEntry entry = mNotificationData.get(key);
+        NotificationEntry entry = getActiveNotificationUnfiltered(key);
         if (entry == null) {
             return;
         }
@@ -463,7 +531,11 @@
         // to keep its lifetime extended.
         cancelLifetimeExtension(entry);
 
-        mNotificationData.update(entry, ranking, notification, "updateNotificationInternal");
+        updateRankingAndSort(ranking, "updateNotificationInternal");
+        StatusBarNotification oldSbn = entry.getSbn();
+        entry.setSbn(notification);
+        mGroupManager.onEntryUpdated(entry, oldSbn);
+
         mNotifLog.log(NotifEvent.NOTIF_UPDATED, entry.getSbn(), entry.getRanking());
         for (NotificationEntryListener listener : mNotificationEntryListeners) {
             listener.onPreEntryUpdated(entry);
@@ -486,8 +558,7 @@
     }
 
     @Override
-    public void updateNotification(StatusBarNotification notification,
-            NotificationListenerService.RankingMap ranking) {
+    public void updateNotification(StatusBarNotification notification, RankingMap ranking) {
         try {
             updateNotificationInternal(notification, ranking);
         } catch (InflationException e) {
@@ -500,16 +571,16 @@
      * @param reason why the notifications are updating
      */
     public void updateNotifications(String reason) {
-        mNotificationData.filterAndSort(reason);
+        reapplyFilterAndSort(reason);
         if (mPresenter != null) {
             mPresenter.updateNotificationViews();
         }
     }
 
     @Override
-    public void updateNotificationRanking(NotificationListenerService.RankingMap rankingMap) {
+    public void updateNotificationRanking(RankingMap rankingMap) {
         List<NotificationEntry> entries = new ArrayList<>();
-        entries.addAll(mNotificationData.getActiveNotifications());
+        entries.addAll(getVisibleNotifications());
         entries.addAll(mPendingNotifications.values());
 
         // Has a copy of the current UI adjustments.
@@ -523,7 +594,7 @@
         }
 
         // Populate notification entries from the new rankings.
-        mNotificationData.updateRanking(rankingMap, "updateNotificationRanking");
+        updateRankingAndSort(rankingMap, "updateNotificationRanking");
         updateRankingOfPendingNotifications(rankingMap);
 
         // By comparing the old and new UI adjustments, reinflate the view accordingly.
@@ -542,8 +613,7 @@
         }
     }
 
-    private void updateRankingOfPendingNotifications(
-            @Nullable NotificationListenerService.RankingMap rankingMap) {
+    private void updateRankingOfPendingNotifications(@Nullable RankingMap rankingMap) {
         if (rankingMap == null) {
             return;
         }
@@ -565,23 +635,35 @@
     }
 
     /**
-     * @return all notification we're currently aware of (both pending and visible notifications)
+     * @return all notifications we're currently aware of (both pending and active notifications)
      */
-    public Set<NotificationEntry> getAllNotifs() {
+    public Set<NotificationEntry> getPendingAndActiveNotifications() {
         Set<NotificationEntry> allNotifs = new HashSet<>(mPendingNotifications.values());
-        allNotifs.addAll(mNotificationData.getActiveNotifications());
+        allNotifs.addAll(mSortedAndFiltered);
         return allNotifs;
     }
 
     /**
+     * Use this method to retrieve a notification entry that has been prepared for presentation.
+     * Note that the notification may be filtered out and never shown to the user.
+     *
+     * @see #getVisibleNotifications() for the currently sorted and filtered list
+     *
+     * @return a {@link NotificationEntry} if it has been prepared, else null
+     */
+    public NotificationEntry getActiveNotificationUnfiltered(String key) {
+        return mActiveNotifications.get(key);
+    }
+
+    /**
      * Gets the pending or visible notification entry with the given key. Returns null if
      * notification doesn't exist.
      */
-    public NotificationEntry getPendingOrCurrentNotif(String key) {
+    public NotificationEntry getPendingOrActiveNotif(String key) {
         if (mPendingNotifications.containsKey(key)) {
             return mPendingNotifications.get(key);
         } else {
-            return mNotificationData.get(key);
+            return mActiveNotifications.get(key);
         }
     }
 
@@ -608,4 +690,136 @@
         }
         return mNotificationRowBinder;
     }
+
+    /*
+     * -----
+     * Annexed from NotificationData below:
+     * Some of these methods may be redundant but require some reworking to remove. For now
+     * we'll try to keep the behavior the same and can simplify these interfaces in another pass
+     */
+
+    /** Internalization of NotificationData#remove */
+    private void removeVisibleNotification(String key) {
+        // no need to synchronize if we're on the main thread dawg
+        Assert.isMainThread();
+
+        NotificationEntry removed = mActiveNotifications.remove(key);
+
+        if (removed == null) return;
+        mGroupManager.onEntryRemoved(removed);
+    }
+
+    /** @return list of active notifications filtered for the current user */
+    public List<NotificationEntry> getActiveNotificationsForCurrentUser() {
+        Assert.isMainThread();
+        ArrayList<NotificationEntry> filtered = new ArrayList<>();
+
+        final int len = mActiveNotifications.size();
+        for (int i = 0; i < len; i++) {
+            NotificationEntry entry = mActiveNotifications.valueAt(i);
+            final StatusBarNotification sbn = entry.getSbn();
+            if (!mKeyguardEnvironment.isNotificationForCurrentProfiles(sbn)) {
+                continue;
+            }
+            filtered.add(entry);
+        }
+
+        return filtered;
+    }
+
+    //TODO: Get rid of this in favor of NotificationUpdateHandler#updateNotificationRanking
+    /**
+     * @param rankingMap the {@link RankingMap} to apply to the current notification list
+     * @param reason the reason for calling this method, for {@link NotifLog}
+     */
+    public void updateRanking(RankingMap rankingMap, String reason) {
+        updateRankingAndSort(rankingMap, reason);
+    }
+
+    /** Resorts / filters the current notification set with the current RankingMap */
+    public void reapplyFilterAndSort(String reason) {
+        updateRankingAndSort(mRankingManager.getRankingMap(), reason);
+    }
+
+    /** Calls to NotificationRankingManager and updates mSortedAndFiltered */
+    private void updateRankingAndSort(@NonNull RankingMap rankingMap, String reason) {
+        mSortedAndFiltered.clear();
+        mSortedAndFiltered.addAll(mRankingManager.updateRanking(
+                rankingMap, mActiveNotifications.values(), reason));
+    }
+
+    /** dump the current active notification list. Called from StatusBar */
+    public void dump(PrintWriter pw, String indent) {
+        pw.println("NotificationEntryManager");
+        int filteredLen = mSortedAndFiltered.size();
+        pw.print(indent);
+        pw.println("active notifications: " + filteredLen);
+        int active;
+        for (active = 0; active < filteredLen; active++) {
+            NotificationEntry e = mSortedAndFiltered.get(active);
+            dumpEntry(pw, indent, active, e);
+        }
+        synchronized (mActiveNotifications) {
+            int totalLen = mActiveNotifications.size();
+            pw.print(indent);
+            pw.println("inactive notifications: " + (totalLen - active));
+            int inactiveCount = 0;
+            for (int i = 0; i < totalLen; i++) {
+                NotificationEntry entry = mActiveNotifications.valueAt(i);
+                if (!mSortedAndFiltered.contains(entry)) {
+                    dumpEntry(pw, indent, inactiveCount, entry);
+                    inactiveCount++;
+                }
+            }
+        }
+    }
+
+    private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
+        pw.print(indent);
+        pw.println("  [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
+        StatusBarNotification n = e.getSbn();
+        pw.print(indent);
+        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
+                + e.getRanking().getImportance());
+        pw.print(indent);
+        pw.println("      notification=" + n.getNotification());
+    }
+
+    /**
+     * This is the answer to the question "what notifications should the user be seeing right now?"
+     * These are sorted and filtered, and directly inform the notification shade what to show
+     *
+     * @return A read-only list of the currently active notifications
+     */
+    public List<NotificationEntry> getVisibleNotifications() {
+        return mReadOnlyNotifications;
+    }
+
+    /** @return A count of the active notifications */
+    public int getActiveNotificationsCount() {
+        return mReadOnlyNotifications.size();
+    }
+
+    /**
+     * @return {@code true} if there is at least one notification that should be visible right now
+     */
+    public boolean hasActiveNotifications() {
+        return mReadOnlyNotifications.size() != 0;
+    }
+
+    /*
+     * End annexation
+     * -----
+     */
+
+
+    /**
+     * Provides access to keyguard state and user settings dependent data.
+     */
+    public interface KeyguardEnvironment {
+        /** true if the device is provisioned (should always be true in practice) */
+        boolean isDeviceProvisioned();
+        /** true if the notification is for the current profiles */
+        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
index b116409..e5f44bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFilter.java
@@ -28,7 +28,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +43,7 @@
     private final NotificationGroupManager mGroupManager = Dependency.get(
             NotificationGroupManager.class);
 
-    private NotificationData.KeyguardEnvironment mEnvironment;
+    private NotificationEntryManager.KeyguardEnvironment mEnvironment;
     private ShadeController mShadeController;
     private ForegroundServiceController mFsc;
     private NotificationLockscreenUserManager mUserManager;
@@ -52,9 +51,9 @@
     @Inject
     public NotificationFilter() {}
 
-    private NotificationData.KeyguardEnvironment getEnvironment() {
+    private NotificationEntryManager.KeyguardEnvironment getEnvironment() {
         if (mEnvironment == null) {
-            mEnvironment = Dependency.get(NotificationData.KeyguardEnvironment.class);
+            mEnvironment = Dependency.get(NotificationEntryManager.KeyguardEnvironment.class);
         }
         return mEnvironment;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 7d09932..66ed864 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 
-import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -189,8 +188,7 @@
             return false;
         }
 
-        final Notification n = sbn.getNotification();
-        if (n.getBubbleMetadata() == null || n.getBubbleMetadata().getIntent() == null) {
+        if (entry.getBubbleMetadata() == null || entry.getBubbleMetadata().getIntent() == null) {
             if (DEBUG) {
                 Log.d(TAG, "No bubble up: notification: " + sbn.getKey()
                         + " doesn't have valid metadata");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 1daf484..1b57308 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -69,20 +69,13 @@
         notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
             public void onPreEntryUpdated(NotificationEntry entry) {
-                final boolean mAmbientStateHasChanged =
+                final boolean ambientStateHasChanged =
                         entry.isAmbient() != entry.getRow().isLowPriority();
-                if (mAmbientStateHasChanged) {
+                if (ambientStateHasChanged) {
+                    // note: entries are removed in onReorderingFinished
                     mLowPriorityReorderingViews.add(entry);
                 }
             }
-
-            @Override
-            public void onPostEntryUpdated(NotificationEntry entry) {
-                // This line is technically not required as we'll get called as the hierarchy
-                // manager will call onReorderingFinished() immediately before this.
-                // TODO: Find a way to make this relationship more explicit
-                mLowPriorityReorderingViews.remove(entry);
-            }
         });
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilder.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
index 17fef68..cefb506 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/CollectionReadyForBuildListener.java
@@ -22,7 +22,7 @@
  * Interface for the class responsible for converting a NotifCollection into the final sorted,
  * filtered, and grouped list of currently visible notifications.
  */
-public interface NotifListBuilder {
+public interface CollectionReadyForBuildListener {
     /**
      * Called after the NotifCollection has received an update from NotificationManager but before
      * it dispatches any change events to its listeners. This is to inform the list builder that
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
new file mode 100644
index 0000000..f9f3266
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/GroupEntry.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import android.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Represents a set of grouped notifications. The final notification list is usually a mix of
+ * GroupEntries and NotificationEntries.
+ */
+public class GroupEntry extends ListEntry {
+    @Nullable private NotificationEntry mSummary;
+    private final List<NotificationEntry> mChildren = new ArrayList<>();
+
+    private final List<NotificationEntry> mUnmodifiableChildren =
+            Collections.unmodifiableList(mChildren);
+
+    GroupEntry(String key) {
+        super(key);
+    }
+
+    @Override
+    public NotificationEntry getRepresentativeEntry() {
+        return mSummary;
+    }
+
+    @Nullable
+    public NotificationEntry getSummary() {
+        return mSummary;
+    }
+
+    public List<NotificationEntry> getChildren() {
+        return mUnmodifiableChildren;
+    }
+
+    void setSummary(@Nullable NotificationEntry summary) {
+        mSummary = summary;
+    }
+
+    void clearChildren() {
+        mChildren.clear();
+    }
+
+    void addChild(NotificationEntry child) {
+        mChildren.add(child);
+    }
+
+    void sortChildren(Comparator<? super NotificationEntry> c) {
+        mChildren.sort(c);
+    }
+
+    List<NotificationEntry> getRawChildren() {
+        return mChildren;
+    }
+
+    public static final GroupEntry ROOT_ENTRY = new GroupEntry("<root>");
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
new file mode 100644
index 0000000..e1268f6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListDumper.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+
+import java.util.List;
+
+
+/**
+ * Utility class for dumping the results of a {@link NotifListBuilder} to a debug string.
+ */
+public class ListDumper {
+
+    /** See class description */
+    public static String dumpList(List<ListEntry> entries) {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < entries.size(); i++) {
+            ListEntry entry = entries.get(i);
+            dumpEntry(entry, Integer.toString(i), "", sb);
+            if (entry instanceof GroupEntry) {
+                GroupEntry ge = (GroupEntry) entry;
+                for (int j = 0; j < ge.getChildren().size(); j++) {
+                    dumpEntry(
+                            ge.getChildren().get(j),
+                            Integer.toString(j),
+                            INDENT,
+                            sb);
+                }
+            }
+        }
+        return sb.toString();
+    }
+
+    private static void dumpEntry(
+            ListEntry entry, String index, String indent, StringBuilder sb) {
+        sb.append(indent)
+                .append("[").append(index).append("] ")
+                .append(entry.getKey())
+                .append(" (parent=")
+                .append(entry.getParent() != null ? entry.getParent().getKey() : null)
+                .append(")\n");
+    }
+
+    private static final String INDENT = "  ";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
new file mode 100644
index 0000000..dc68c4b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ListEntry.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import android.annotation.Nullable;
+
+/**
+ * Abstract superclass for top-level entries, i.e. things that can appear in the final notification
+ * list shown to users. In practice, this means either GroupEntries or NotificationEntries.
+ */
+public abstract class ListEntry {
+    private final String mKey;
+
+    @Nullable private GroupEntry mParent;
+    @Nullable private GroupEntry mPreviousParent;
+    private int mSection;
+    int mFirstAddedIteration = -1;
+
+    ListEntry(String key) {
+        mKey = key;
+    }
+
+    public String getKey() {
+        return mKey;
+    }
+
+    /**
+     * Should return the "representative entry" for this ListEntry. For NotificationEntries, its
+     * the entry itself. For groups, it should be the summary. This method exists to interface with
+     * legacy code that expects groups to also be NotificationEntries.
+     */
+    public abstract NotificationEntry getRepresentativeEntry();
+
+    @Nullable public GroupEntry getParent() {
+        return mParent;
+    }
+
+    void setParent(@Nullable GroupEntry parent) {
+        mParent = parent;
+    }
+
+    @Nullable public GroupEntry getPreviousParent() {
+        return mPreviousParent;
+    }
+
+    void setPreviousParent(@Nullable GroupEntry previousParent) {
+        mPreviousParent = previousParent;
+    }
+
+    /** The section this notification was assigned to (0 to N-1, where N is number of sections). */
+    public int getSection() {
+        return mSection;
+    }
+
+    void setSection(int section) {
+        mSection = section;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index b551352..6f085c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -95,7 +95,7 @@
     private final Collection<NotificationEntry> mReadOnlyNotificationSet =
             Collections.unmodifiableCollection(mNotificationSet.values());
 
-    @Nullable private NotifListBuilder mListBuilder;
+    @Nullable private CollectionReadyForBuildListener mBuildListener;
     private final List<NotifCollectionListener> mNotifCollectionListeners = new ArrayList<>();
     private final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
 
@@ -123,9 +123,9 @@
      * Sets the class responsible for converting the collection into the list of currently-visible
      * notifications.
      */
-    public void setListBuilder(NotifListBuilder listBuilder) {
+    public void setBuildListener(CollectionReadyForBuildListener buildListener) {
         Assert.isMainThread();
-        mListBuilder = listBuilder;
+        mBuildListener = buildListener;
     }
 
     /**
@@ -282,8 +282,8 @@
     }
 
     private void rebuildList() {
-        if (mListBuilder != null) {
-            mListBuilder.onBuildList(mReadOnlyNotificationSet);
+        if (mBuildListener != null) {
+            mBuildListener.onBuildList(mReadOnlyNotificationSet);
         }
     }
 
@@ -339,8 +339,8 @@
 
     private void dispatchOnEntryAdded(NotificationEntry entry) {
         mAmDispatchingToOtherCode = true;
-        if (mListBuilder != null) {
-            mListBuilder.onBeginDispatchToListeners();
+        if (mBuildListener != null) {
+            mBuildListener.onBeginDispatchToListeners();
         }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryAdded(entry);
@@ -350,8 +350,8 @@
 
     private void dispatchOnEntryUpdated(NotificationEntry entry) {
         mAmDispatchingToOtherCode = true;
-        if (mListBuilder != null) {
-            mListBuilder.onBeginDispatchToListeners();
+        if (mBuildListener != null) {
+            mBuildListener.onBeginDispatchToListeners();
         }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryUpdated(entry);
@@ -364,8 +364,8 @@
             @CancellationReason int reason,
             boolean removedByUser) {
         mAmDispatchingToOtherCode = true;
-        if (mListBuilder != null) {
-            mListBuilder.onBeginDispatchToListeners();
+        if (mBuildListener != null) {
+            mBuildListener.onBeginDispatchToListeners();
         }
         for (NotifCollectionListener listener : mNotifCollectionListeners) {
             listener.onEntryRemoved(entry, reason, removedByUser);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
new file mode 100644
index 0000000..21a4b4f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImpl.java
@@ -0,0 +1,737 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static com.android.systemui.statusbar.notification.collection.GroupEntry.ROOT_ENTRY;
+import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_PENDING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_BUILD_STARTED;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FILTERING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_FINALIZING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_IDLE;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
+import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
+
+import android.annotation.MainThread;
+import android.annotation.Nullable;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.util.Assert;
+import com.android.systemui.util.time.SystemClock;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * The implementation of {@link NotifListBuilder}.
+ */
+@MainThread
+@Singleton
+public class NotifListBuilderImpl implements NotifListBuilder {
+
+    private final SystemClock mSystemClock;
+
+    private final List<ListEntry> mNotifList = new ArrayList<>();
+
+    private final PipelineState mPipelineState = new PipelineState();
+    private final Map<String, GroupEntry> mGroups = new ArrayMap<>();
+    private Collection<NotificationEntry> mAllEntries = Collections.emptyList();
+    private final List<ListEntry> mNewEntries = new ArrayList<>();
+    private int mIterationCount = 0;
+
+    private final List<NotifFilter> mNotifFilters = new ArrayList<>();
+    private final List<NotifPromoter> mNotifPromoters = new ArrayList<>();
+    private final List<NotifComparator> mNotifComparators = new ArrayList<>();
+    private SectionsProvider mSectionsProvider = new DefaultSectionsProvider();
+
+    private final List<OnBeforeTransformGroupsListener> mOnBeforeTransformGroupsListeners =
+            new ArrayList<>();
+    private final List<OnBeforeSortListener> mOnBeforeSortListeners =
+            new ArrayList<>();
+    private final List<OnBeforeRenderListListener> mOnBeforeRenderListListeners =
+            new ArrayList<>();
+    @Nullable private OnRenderListListener mOnRenderListListener;
+
+    private final List<ListEntry> mReadOnlyNotifList = Collections.unmodifiableList(mNotifList);
+
+    @Inject
+    public NotifListBuilderImpl(SystemClock systemClock) {
+        Assert.isMainThread();
+        mSystemClock = systemClock;
+    }
+
+    /**
+     * Attach the list builder to the NotifCollection. After this is called, it will start building
+     * the notif list in response to changes to the colletion.
+     */
+    public void attach(NotifCollection collection) {
+        Assert.isMainThread();
+        collection.setBuildListener(mReadyForBuildListener);
+    }
+
+    /**
+     * Registers the listener that's responsible for rendering the notif list to the screen. Called
+     * At the very end of pipeline execution, after all other listeners and pluggables have fired.
+     */
+    public void setOnRenderListListener(OnRenderListListener onRenderListListener) {
+        Assert.isMainThread();
+
+        mPipelineState.requireState(STATE_IDLE);
+        mOnRenderListListener = onRenderListListener;
+    }
+
+    @Override
+    public void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener) {
+        Assert.isMainThread();
+
+        mPipelineState.requireState(STATE_IDLE);
+        mOnBeforeTransformGroupsListeners.add(listener);
+    }
+
+    @Override
+    public void addOnBeforeSortListener(OnBeforeSortListener listener) {
+        Assert.isMainThread();
+
+        mPipelineState.requireState(STATE_IDLE);
+        mOnBeforeSortListeners.add(listener);
+    }
+
+    @Override
+    public void addOnBeforeRenderListListener(OnBeforeRenderListListener listener) {
+        Assert.isMainThread();
+
+        mPipelineState.requireState(STATE_IDLE);
+        mOnBeforeRenderListListeners.add(listener);
+    }
+
+    @Override
+    public void addFilter(NotifFilter filter) {
+        Assert.isMainThread();
+        mPipelineState.requireState(STATE_IDLE);
+
+        mNotifFilters.add(filter);
+        filter.setInvalidationListener(this::onFilterInvalidated);
+    }
+
+    @Override
+    public void addPromoter(NotifPromoter promoter) {
+        Assert.isMainThread();
+        mPipelineState.requireState(STATE_IDLE);
+
+        mNotifPromoters.add(promoter);
+        promoter.setInvalidationListener(this::onPromoterInvalidated);
+    }
+
+    @Override
+    public void setSectionsProvider(SectionsProvider provider) {
+        Assert.isMainThread();
+        mPipelineState.requireState(STATE_IDLE);
+
+        mSectionsProvider = provider;
+        provider.setInvalidationListener(this::onSectionsProviderInvalidated);
+    }
+
+    @Override
+    public void setComparators(List<NotifComparator> comparators) {
+        Assert.isMainThread();
+        mPipelineState.requireState(STATE_IDLE);
+
+        mNotifComparators.clear();
+        for (NotifComparator comparator : comparators) {
+            mNotifComparators.add(comparator);
+            comparator.setInvalidationListener(this::onNotifComparatorInvalidated);
+        }
+    }
+
+    @Override
+    public List<ListEntry> getActiveNotifs() {
+        Assert.isMainThread();
+        return mReadOnlyNotifList;
+    }
+
+    private final CollectionReadyForBuildListener mReadyForBuildListener =
+            new CollectionReadyForBuildListener() {
+                @Override
+                public void onBeginDispatchToListeners() {
+                    Assert.isMainThread();
+                    mPipelineState.incrementTo(STATE_BUILD_PENDING);
+                }
+
+                @Override
+                public void onBuildList(Collection<NotificationEntry> entries) {
+                    Assert.isMainThread();
+                    mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
+
+                    Log.i(TAG, "Build request received from NotifCollection");
+                    mAllEntries = entries;
+                    buildList();
+                }
+            };
+
+    private void onFilterInvalidated(NotifFilter filter) {
+        Assert.isMainThread();
+
+        // TODO: Convert these log statements (here and elsewhere) into timeline logging
+        Log.i(TAG, String.format(
+                "Filter \"%s\" invalidated; pipeline state is %d",
+                filter.getName(),
+                mPipelineState.getState()));
+
+        rebuildListIfBefore(STATE_FILTERING);
+    }
+
+    private void onPromoterInvalidated(NotifPromoter filter) {
+        Assert.isMainThread();
+
+        Log.i(TAG, String.format(
+                "NotifPromoter \"%s\" invalidated; pipeline state is %d",
+                filter.getName(),
+                mPipelineState.getState()));
+
+        rebuildListIfBefore(STATE_TRANSFORMING);
+    }
+
+    private void onSectionsProviderInvalidated(SectionsProvider provider) {
+        Assert.isMainThread();
+
+        Log.i(TAG, String.format(
+                "Sections provider \"%s\" invalidated; pipeline state is %d",
+                provider.getName(),
+                mPipelineState.getState()));
+
+        rebuildListIfBefore(STATE_SORTING);
+    }
+
+    private void onNotifComparatorInvalidated(NotifComparator comparator) {
+        Assert.isMainThread();
+
+        Log.i(TAG, String.format(
+                "Comparator \"%s\" invalidated; pipeline state is %d",
+                comparator.getName(),
+                mPipelineState.getState()));
+
+        rebuildListIfBefore(STATE_SORTING);
+    }
+
+    /**
+     * The core algorithm of the pipeline. See the top comment in {@link NotifListBuilder} for
+     * details on our contracts with other code.
+     *
+     * Once the build starts we are very careful to protect against reentrant code. Anything that
+     * tries to invalidate itself after the pipeline has passed it by will return in an exception.
+     * In general, we should be extremely sensitive to client code doing things in the wrong order;
+     * if we detect that behavior, we should crash instantly.
+     */
+    private void buildList() {
+        Log.i(TAG, "Starting notif list build #" + mIterationCount + "...");
+
+        mPipelineState.requireIsBefore(STATE_BUILD_STARTED);
+        mPipelineState.setState(STATE_BUILD_STARTED);
+
+        // Step 1: Filtering and initial grouping
+        // Filter out any notifs that shouldn't be shown right now and cluster any that are part of
+        // a group
+        mPipelineState.incrementTo(STATE_FILTERING);
+        mNotifList.clear();
+        mNewEntries.clear();
+        filterAndGroup(mAllEntries, mNotifList, mNewEntries);
+        pruneIncompleteGroups(mNotifList, mNewEntries);
+
+        // Step 2: Group transforming
+        // Move some notifs out of their groups and up to top-level (mostly used for heads-upping)
+        dispatchOnBeforeTransformGroups(mReadOnlyNotifList, mNewEntries);
+        mPipelineState.incrementTo(STATE_TRANSFORMING);
+        promoteNotifs(mNotifList);
+        pruneIncompleteGroups(mNotifList, mNewEntries);
+
+        // Step 3: Sort
+        // Assign each top-level entry a section, then sort the list by section and then within
+        // section by our list of custom comparators
+        dispatchOnBeforeSort(mReadOnlyNotifList);
+        mPipelineState.incrementTo(STATE_SORTING);
+        sortList();
+
+        // Step 4: Lock in our group structure and log anything that's changed since the last run
+        mPipelineState.incrementTo(STATE_FINALIZING);
+        logParentingChanges();
+        freeEmptyGroups();
+
+        // Step 5: Dispatch the new list, first to any listeners and then to the view layer
+        Log.i(TAG, "List finalized, is:\n" + dumpList(mNotifList));
+        Log.i(TAG, "Dispatching final list to listeners...");
+        dispatchOnBeforeRenderList(mReadOnlyNotifList);
+        if (mOnRenderListListener != null) {
+            mOnRenderListListener.onRenderList(mReadOnlyNotifList);
+        }
+
+        // Step 6: We're done!
+        Log.i(TAG, "Notif list build #" + mIterationCount + " completed");
+        mPipelineState.setState(STATE_IDLE);
+        mIterationCount++;
+    }
+
+    private void filterAndGroup(
+            Collection<NotificationEntry> entries,
+            List<ListEntry> out,
+            List<ListEntry> newlyVisibleEntries) {
+
+        long now = mSystemClock.uptimeMillis();
+
+        for (GroupEntry group : mGroups.values()) {
+            group.setPreviousParent(group.getParent());
+            group.setParent(null);
+            group.clearChildren();
+            group.setSummary(null);
+        }
+
+        for (NotificationEntry entry : entries) {
+            entry.setPreviousParent(entry.getParent());
+            entry.setParent(null);
+
+            // See if we should filter out this notification
+            boolean shouldFilterOut = applyFilters(entry, now);
+            if (shouldFilterOut) {
+                continue;
+            }
+
+            if (entry.mFirstAddedIteration == -1) {
+                entry.mFirstAddedIteration = mIterationCount;
+                newlyVisibleEntries.add(entry);
+            }
+
+            // Otherwise, group it
+            if (entry.getSbn().isGroup()) {
+                final String topLevelKey = entry.getSbn().getGroupKey();
+
+                GroupEntry group = mGroups.get(topLevelKey);
+                if (group == null) {
+                    group = new GroupEntry(topLevelKey);
+                    group.mFirstAddedIteration = mIterationCount;
+                    newlyVisibleEntries.add(group);
+                    mGroups.put(topLevelKey, group);
+                }
+                if (group.getParent() == null) {
+                    group.setParent(ROOT_ENTRY);
+                    out.add(group);
+                }
+
+                entry.setParent(group);
+
+                if (entry.getSbn().getNotification().isGroupSummary()) {
+                    final NotificationEntry existingSummary = group.getSummary();
+
+                    if (existingSummary == null) {
+                        group.setSummary(entry);
+                    } else {
+                        Log.w(TAG, String.format(
+                                "Duplicate summary for group '%s': '%s' vs. '%s'",
+                                group.getKey(),
+                                existingSummary.getKey(),
+                                entry.getKey()));
+
+                        // Use whichever one was posted most recently
+                        if (entry.getSbn().getPostTime()
+                                > existingSummary.getSbn().getPostTime()) {
+                            group.setSummary(entry);
+                            annulAddition(existingSummary, out, newlyVisibleEntries);
+                        } else {
+                            annulAddition(entry, out, newlyVisibleEntries);
+                        }
+                    }
+                } else {
+                    group.addChild(entry);
+                }
+
+            } else {
+
+                final String topLevelKey = entry.getKey();
+                if (mGroups.containsKey(topLevelKey)) {
+                    Log.wtf(TAG, "Duplicate non-group top-level key: " + topLevelKey);
+                } else {
+                    entry.setParent(ROOT_ENTRY);
+                    out.add(entry);
+                }
+            }
+        }
+    }
+
+    private void promoteNotifs(List<ListEntry> list) {
+        for (int i = 0; i < list.size(); i++) {
+            final ListEntry tle = list.get(i);
+
+            if (tle instanceof GroupEntry) {
+                final GroupEntry group = (GroupEntry) tle;
+
+                group.getRawChildren().removeIf(child -> {
+                    final boolean shouldPromote = applyTopLevelPromoters(child);
+
+                    if (shouldPromote) {
+                        child.setParent(ROOT_ENTRY);
+                        list.add(child);
+                    }
+
+                    return shouldPromote;
+                });
+            }
+        }
+    }
+
+    private void pruneIncompleteGroups(
+            List<ListEntry> shadeList,
+            List<ListEntry> newlyVisibleEntries) {
+
+        for (int i = 0; i < shadeList.size(); i++) {
+            final ListEntry tle = shadeList.get(i);
+
+            if (tle instanceof GroupEntry) {
+                final GroupEntry group = (GroupEntry) tle;
+                final List<NotificationEntry> children = group.getRawChildren();
+
+                if (group.getSummary() != null && children.size() == 0) {
+                    shadeList.remove(i);
+                    i--;
+
+                    NotificationEntry summary = group.getSummary();
+                    summary.setParent(ROOT_ENTRY);
+                    shadeList.add(summary);
+
+                    group.setSummary(null);
+                    annulAddition(group, shadeList, newlyVisibleEntries);
+
+                } else if (group.getSummary() == null
+                        || children.size() < MIN_CHILDREN_FOR_GROUP) {
+                    // If the group doesn't provide a summary or is too small, ignore it and add
+                    // its children (if any) directly to top-level.
+
+                    shadeList.remove(i);
+                    i--;
+
+                    if (group.getSummary() != null) {
+                        final NotificationEntry summary = group.getSummary();
+                        group.setSummary(null);
+                        annulAddition(summary, shadeList, newlyVisibleEntries);
+                    }
+
+                    for (int j = 0; j < children.size(); j++) {
+                        final NotificationEntry child = children.get(j);
+                        child.setParent(ROOT_ENTRY);
+                        shadeList.add(child);
+                    }
+                    children.clear();
+
+                    annulAddition(group, shadeList, newlyVisibleEntries);
+                }
+            }
+        }
+    }
+
+    /**
+     * If a ListEntry was added to the shade list and then later removed (e.g. because it was a
+     * group that was broken up), this method will erase any bookkeeping traces of that addition
+     * and/or check that they were already erased.
+     *
+     * Before calling this method, the entry must already have been removed from its parent. If
+     * it's a group, its summary must be null and its children must be empty.
+     */
+    private void annulAddition(
+            ListEntry entry,
+            List<ListEntry> shadeList,
+            List<ListEntry> newlyVisibleEntries) {
+
+        // This function does very little, but if any of its assumptions are violated (and it has a
+        // lot of them), it will put the system into an inconsistent state. So we check all of them
+        // here.
+
+        if (entry.getParent() == null || entry.mFirstAddedIteration == -1) {
+            throw new IllegalStateException(
+                    "Cannot nullify addition of " + entry.getKey() + ": no such addition. ("
+                            + entry.getParent() + " " + entry.mFirstAddedIteration + ")");
+        }
+
+        if (entry.getParent() == ROOT_ENTRY) {
+            if (shadeList.contains(entry)) {
+                throw new IllegalStateException("Cannot nullify addition of " + entry.getKey()
+                        + ": it's still in the shade list.");
+            }
+        }
+
+        if (entry instanceof GroupEntry) {
+            GroupEntry ge = (GroupEntry) entry;
+            if (ge.getSummary() != null) {
+                throw new IllegalStateException(
+                        "Cannot nullify group " + ge.getKey() + ": summary is not null");
+            }
+            if (!ge.getChildren().isEmpty()) {
+                throw new IllegalStateException(
+                        "Cannot nullify group " + ge.getKey() + ": still has children");
+            }
+        } else if (entry instanceof NotificationEntry) {
+            if (entry == entry.getParent().getSummary()
+                    || entry.getParent().getChildren().contains(entry)) {
+                throw new IllegalStateException("Cannot nullify addition of child "
+                        + entry.getKey() + ": it's still attached to its parent.");
+            }
+        }
+
+        entry.setParent(null);
+        if (entry.mFirstAddedIteration == mIterationCount) {
+            if (!newlyVisibleEntries.remove(entry)) {
+                throw new IllegalStateException("Cannot late-filter entry " + entry.getKey() + " "
+                        + entry + " from " + newlyVisibleEntries + " "
+                        + entry.mFirstAddedIteration);
+            }
+            entry.mFirstAddedIteration = -1;
+        }
+    }
+
+    private void sortList() {
+        // Assign sections to top-level elements and sort their children
+        for (ListEntry entry : mNotifList) {
+            entry.setSection(mSectionsProvider.getSection(entry));
+            if (entry instanceof GroupEntry) {
+                GroupEntry parent = (GroupEntry) entry;
+                for (NotificationEntry child : parent.getChildren()) {
+                    child.setSection(0);
+                }
+                parent.sortChildren(sChildComparator);
+            }
+        }
+
+        // Finally, sort all top-level elements
+        mNotifList.sort(mTopLevelComparator);
+    }
+
+    private void freeEmptyGroups() {
+        mGroups.values().removeIf(ge -> ge.getSummary() == null && ge.getChildren().isEmpty());
+    }
+
+    private void logParentingChanges() {
+        for (NotificationEntry entry : mAllEntries) {
+            if (entry.getParent() != entry.getPreviousParent()) {
+                Log.i(TAG, String.format(
+                        "%s: parent changed from %s to %s",
+                        entry.getKey(),
+                        entry.getPreviousParent() == null
+                                ? "null" : entry.getPreviousParent().getKey(),
+                        entry.getParent() == null
+                                ? "null" : entry.getParent().getKey()));
+            }
+        }
+        for (GroupEntry group : mGroups.values()) {
+            if (group.getParent() != group.getPreviousParent()) {
+                Log.i(TAG, String.format(
+                        "%s: parent changed from %s to %s",
+                        group.getKey(),
+                        group.getPreviousParent() == null
+                                ? "null" : group.getPreviousParent().getKey(),
+                        group.getParent() == null
+                                ? "null" : group.getParent().getKey()));
+            }
+        }
+    }
+
+    private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
+
+        int cmp = Integer.compare(o1.getSection(), o2.getSection());
+
+        if (cmp == 0) {
+            for (int i = 0; i < mNotifComparators.size(); i++) {
+                cmp = mNotifComparators.get(i).compare(o1, o2);
+                if (cmp != 0) {
+                    break;
+                }
+            }
+        }
+
+        final NotificationEntry rep1 = o1.getRepresentativeEntry();
+        final NotificationEntry rep2 = o2.getRepresentativeEntry();
+
+        if (cmp == 0) {
+            cmp = rep1.getRanking().getRank() - rep2.getRanking().getRank();
+        }
+
+        if (cmp == 0) {
+            cmp = Long.compare(
+                    rep2.getSbn().getNotification().when,
+                    rep1.getSbn().getNotification().when);
+        }
+
+        return cmp;
+    };
+
+    private static final Comparator<NotificationEntry> sChildComparator = (o1, o2) -> {
+        int cmp = o1.getRanking().getRank() - o2.getRanking().getRank();
+
+        if (cmp == 0) {
+            cmp = Long.compare(
+                    o2.getSbn().getNotification().when,
+                    o1.getSbn().getNotification().when);
+        }
+
+        return cmp;
+    };
+
+    private boolean applyFilters(NotificationEntry entry, long now) {
+        NotifFilter filter = findRejectingFilter(entry, now);
+
+        if (filter != entry.mExcludingFilter) {
+            if (entry.mExcludingFilter == null) {
+                Log.i(TAG, String.format(
+                        "%s: filtered out by '%s'",
+                        entry.getKey(),
+                        filter.getName()));
+            } else if (filter == null) {
+                Log.i(TAG, String.format(
+                        "%s: no longer filtered out (previous filter was '%s')",
+                        entry.getKey(),
+                        entry.mExcludingFilter.getName()));
+            } else {
+                Log.i(TAG, String.format(
+                        "%s: filter changed: '%s' -> '%s'",
+                        entry.getKey(),
+                        entry.mExcludingFilter,
+                        filter));
+            }
+
+            // Note that groups and summaries can also be filtered out later if they're part of a
+            // malformed group. We currently don't have a great way to track that beyond parenting
+            // change logs. Consider adding something similar to mExcludingFilter for them.
+            entry.mExcludingFilter = filter;
+        }
+
+        return filter != null;
+    }
+
+    @Nullable private NotifFilter findRejectingFilter(NotificationEntry entry, long now) {
+        for (int i = 0; i < mNotifFilters.size(); i++) {
+            NotifFilter filter = mNotifFilters.get(i);
+            if (filter.shouldFilterOut(entry, now)) {
+                return filter;
+            }
+        }
+        return null;
+    }
+
+    private boolean applyTopLevelPromoters(NotificationEntry entry) {
+        NotifPromoter promoter = findPromoter(entry);
+
+        if (promoter != entry.mNotifPromoter) {
+            if (entry.mNotifPromoter == null) {
+                Log.i(TAG, String.format(
+                        "%s: Entry promoted to top level by '%s'",
+                        entry.getKey(),
+                        promoter.getName()));
+            } else if (promoter == null) {
+                Log.i(TAG, String.format(
+                        "%s: Entry is no longer promoted to top level (previous promoter was '%s')",
+                        entry.getKey(),
+                        entry.mNotifPromoter.getName()));
+            } else {
+                Log.i(TAG, String.format(
+                        "%s: Top-level promoter changed: '%s' -> '%s'",
+                        entry.getKey(),
+                        entry.mNotifPromoter,
+                        promoter));
+            }
+
+            entry.mNotifPromoter = promoter;
+        }
+
+        return promoter != null;
+    }
+
+    @Nullable private NotifPromoter findPromoter(NotificationEntry entry) {
+        for (int i = 0; i < mNotifPromoters.size(); i++) {
+            NotifPromoter promoter = mNotifPromoters.get(i);
+            if (promoter.shouldPromoteToTopLevel(entry)) {
+                return promoter;
+            }
+        }
+        return null;
+    }
+
+    private void rebuildListIfBefore(@PipelineState.StateName int state) {
+        mPipelineState.requireIsBefore(state);
+        if (mPipelineState.is(STATE_IDLE)) {
+            buildList();
+        }
+    }
+
+    private void dispatchOnBeforeTransformGroups(
+            List<ListEntry> entries,
+            List<ListEntry> newlyVisibleEntries) {
+        for (int i = 0; i < mOnBeforeTransformGroupsListeners.size(); i++) {
+            mOnBeforeTransformGroupsListeners.get(i)
+                    .onBeforeTransformGroups(entries, newlyVisibleEntries);
+        }
+    }
+
+    private void dispatchOnBeforeSort(List<ListEntry> entries) {
+        for (int i = 0; i < mOnBeforeSortListeners.size(); i++) {
+            mOnBeforeSortListeners.get(i).onBeforeSort(entries);
+        }
+    }
+
+    private void dispatchOnBeforeRenderList(List<ListEntry> entries) {
+        for (int i = 0; i < mOnBeforeRenderListListeners.size(); i++) {
+            mOnBeforeRenderListListeners.get(i).onBeforeRenderList(entries);
+        }
+    }
+
+    /** See {@link #setOnRenderListListener(OnRenderListListener)} */
+    public interface OnRenderListListener {
+        /**
+         * Called with the final filtered, grouped, and sorted list.
+         *
+         * @param entries A read-only view into the current notif list. Note that this list is
+         *                backed by the live list and will change in response to new pipeline runs.
+         */
+        void onRenderList(List<ListEntry> entries);
+    }
+
+    private static class DefaultSectionsProvider extends SectionsProvider {
+        DefaultSectionsProvider() {
+            super("DefaultSectionsProvider");
+        }
+
+        @Override
+        public int getSection(ListEntry entry) {
+            return 0;
+        }
+    }
+
+    private static final String TAG = "NotifListBuilderImpl";
+
+    private static final int MIN_CHILDREN_FOR_GROUP = 2;
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
deleted file mode 100644
index a0229d1..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ /dev/null
@@ -1,500 +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.systemui.statusbar.notification.collection;
-
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
-
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.Person;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.NotificationListenerService.RankingMap;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
-import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.logging.NotifEvent;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Objects;
-
-import javax.inject.Inject;
-
-/**
- * The list of currently displaying notifications.
- */
-public class NotificationData {
-    private static final String TAG = "NotificationData";
-
-    private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
-
-    /**
-     * These dependencies are late init-ed
-     */
-    private KeyguardEnvironment mEnvironment;
-    private NotificationMediaManager mMediaManager;
-
-    private HeadsUpManager mHeadsUpManager;
-
-    private final ArrayMap<String, NotificationEntry> mEntries = new ArrayMap<>();
-    private final ArrayList<NotificationEntry> mSortedAndFiltered = new ArrayList<>();
-
-    private final NotificationGroupManager mGroupManager =
-            Dependency.get(NotificationGroupManager.class);
-
-    private RankingMap mRankingMap;
-    private final Ranking mTmpRanking = new Ranking();
-    private final boolean mUsePeopleFiltering;
-    private final NotifLog mNotifLog;
-    private final PeopleNotificationIdentifier mPeopleNotificationIdentifier;
-
-    @Inject
-    public NotificationData(
-            NotificationSectionsFeatureManager sectionsFeatureManager,
-            NotifLog notifLog,
-            PeopleNotificationIdentifier peopleNotificationIdentifier) {
-        mUsePeopleFiltering = sectionsFeatureManager.isFilteringEnabled();
-        mNotifLog = notifLog;
-        mPeopleNotificationIdentifier = peopleNotificationIdentifier;
-    }
-
-    public void setHeadsUpManager(HeadsUpManager headsUpManager) {
-        mHeadsUpManager = headsUpManager;
-    }
-
-    @VisibleForTesting
-    protected final Comparator<NotificationEntry> mRankingComparator =
-            new Comparator<NotificationEntry>() {
-        @Override
-        public int compare(NotificationEntry a, NotificationEntry b) {
-            final StatusBarNotification na = a.getSbn();
-            final StatusBarNotification nb = b.getSbn();
-            int aRank = getRank(a.getKey());
-            int bRank = getRank(b.getKey());
-
-            boolean aPeople = isPeopleNotification(a);
-            boolean bPeople = isPeopleNotification(b);
-
-            boolean aMedia = isImportantMedia(a);
-            boolean bMedia = isImportantMedia(b);
-
-            boolean aSystemMax = isSystemMax(a);
-            boolean bSystemMax = isSystemMax(b);
-
-            boolean aHeadsUp = a.isRowHeadsUp();
-            boolean bHeadsUp = b.isRowHeadsUp();
-
-            if (mUsePeopleFiltering && aPeople != bPeople) {
-                return aPeople ? -1 : 1;
-            } else if (aHeadsUp != bHeadsUp) {
-                return aHeadsUp ? -1 : 1;
-            } else if (aHeadsUp) {
-                // Provide consistent ranking with headsUpManager
-                return mHeadsUpManager.compare(a, b);
-            } else if (aMedia != bMedia) {
-                // Upsort current media notification.
-                return aMedia ? -1 : 1;
-            } else if (aSystemMax != bSystemMax) {
-                // Upsort PRIORITY_MAX system notifications
-                return aSystemMax ? -1 : 1;
-            } else if (a.isHighPriority() != b.isHighPriority()) {
-                return -1 * Boolean.compare(a.isHighPriority(), b.isHighPriority());
-            } else if (aRank != bRank) {
-                return aRank - bRank;
-            } else {
-                return Long.compare(nb.getNotification().when, na.getNotification().when);
-            }
-        }
-    };
-
-    private KeyguardEnvironment getEnvironment() {
-        if (mEnvironment == null) {
-            mEnvironment = Dependency.get(KeyguardEnvironment.class);
-        }
-        return mEnvironment;
-    }
-
-    private NotificationMediaManager getMediaManager() {
-        if (mMediaManager == null) {
-            mMediaManager = Dependency.get(NotificationMediaManager.class);
-        }
-        return mMediaManager;
-    }
-
-    /**
-     * Returns the sorted list of active notifications (depending on {@link KeyguardEnvironment}
-     *
-     * <p>
-     * This call doesn't update the list of active notifications. Call {@link #filterAndSort()}
-     * when the environment changes.
-     * <p>
-     * Don't hold on to or modify the returned list.
-     */
-    public ArrayList<NotificationEntry> getActiveNotifications() {
-        return mSortedAndFiltered;
-    }
-
-    public ArrayList<NotificationEntry> getNotificationsForCurrentUser() {
-        synchronized (mEntries) {
-            final int len = mEntries.size();
-            ArrayList<NotificationEntry> filteredForUser = new ArrayList<>(len);
-
-            for (int i = 0; i < len; i++) {
-                NotificationEntry entry = mEntries.valueAt(i);
-                final StatusBarNotification sbn = entry.getSbn();
-                if (!getEnvironment().isNotificationForCurrentProfiles(sbn)) {
-                    continue;
-                }
-                filteredForUser.add(entry);
-            }
-            return filteredForUser;
-        }
-    }
-
-    public NotificationEntry get(String key) {
-        return mEntries.get(key);
-    }
-
-    public void add(NotificationEntry entry) {
-        synchronized (mEntries) {
-            mEntries.put(entry.getSbn().getKey(), entry);
-        }
-        mGroupManager.onEntryAdded(entry);
-
-        updateRankingAndSort(mRankingMap, "addEntry=" + entry.getSbn());
-    }
-
-    public NotificationEntry remove(String key, RankingMap ranking) {
-        NotificationEntry removed;
-        synchronized (mEntries) {
-            removed = mEntries.remove(key);
-        }
-        if (removed == null) return null;
-        mGroupManager.onEntryRemoved(removed);
-        updateRankingAndSort(ranking, "removeEntry=" + removed.getSbn());
-        return removed;
-    }
-
-    /** Updates the given notification entry with the provided ranking. */
-    public void update(
-            NotificationEntry entry,
-            RankingMap ranking,
-            StatusBarNotification notification,
-            String reason) {
-        updateRanking(ranking, reason);
-        final StatusBarNotification oldNotification = entry.getSbn();
-        entry.setSbn(notification);
-        mGroupManager.onEntryUpdated(entry, oldNotification);
-    }
-
-    /**
-     * Update ranking and trigger a re-sort
-     */
-    public void updateRanking(RankingMap ranking, String reason) {
-        updateRankingAndSort(ranking, reason);
-    }
-
-    /**
-     * Returns true if this notification should be displayed in the high-priority notifications
-     * section
-     */
-    public boolean isHighPriority(StatusBarNotification statusBarNotification) {
-        if (mRankingMap != null) {
-            getRanking(statusBarNotification.getKey(), mTmpRanking);
-            if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
-                    || hasHighPriorityCharacteristics(
-                            mTmpRanking.getChannel(), statusBarNotification)) {
-                return true;
-            }
-            if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
-                final ArrayList<NotificationEntry> logicalChildren =
-                        mGroupManager.getLogicalChildren(statusBarNotification);
-                for (NotificationEntry child : logicalChildren) {
-                    if (isHighPriority(child.getSbn())) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    private boolean hasHighPriorityCharacteristics(NotificationChannel channel,
-            StatusBarNotification statusBarNotification) {
-
-        if (isImportantOngoing(statusBarNotification.getNotification())
-                || statusBarNotification.getNotification().hasMediaSession()
-                || hasPerson(statusBarNotification.getNotification())
-                || hasStyle(statusBarNotification.getNotification(),
-                Notification.MessagingStyle.class)) {
-            // Users who have long pressed and demoted to silent should not see the notification
-            // in the top section
-            if (channel != null && channel.hasUserSetImportance()) {
-                return false;
-            }
-            return true;
-        }
-
-        return false;
-    }
-
-    private boolean isImportantOngoing(Notification notification) {
-        return notification.isForegroundService()
-                && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW;
-    }
-
-    private boolean hasStyle(Notification notification, Class targetStyle) {
-        Class<? extends Notification.Style> style = notification.getNotificationStyle();
-        return targetStyle.equals(style);
-    }
-
-    private boolean hasPerson(Notification notification) {
-        // TODO: cache favorite and recent contacts to check contact affinity
-        ArrayList<Person> people = notification.extras != null
-                ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
-                : new ArrayList<>();
-        return people != null && !people.isEmpty();
-    }
-
-    public boolean isAmbient(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.isAmbient();
-        }
-        return false;
-    }
-
-    public int getVisibilityOverride(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getVisibilityOverride();
-        }
-        return Ranking.VISIBILITY_NO_OVERRIDE;
-    }
-
-    public List<SnoozeCriterion> getSnoozeCriteria(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getSnoozeCriteria();
-        }
-        return null;
-    }
-
-    public NotificationChannel getChannel(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getChannel();
-        }
-        return null;
-    }
-
-    public int getRank(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.getRank();
-        }
-        return 0;
-    }
-
-    private boolean isImportantMedia(NotificationEntry e) {
-        int importance = e.getRanking().getImportance();
-        boolean media = e.getKey().equals(getMediaManager().getMediaNotificationKey())
-                && importance > NotificationManager.IMPORTANCE_MIN;
-
-        return media;
-    }
-
-    private boolean isSystemMax(NotificationEntry e) {
-        int importance = e.getRanking().getImportance();
-        boolean sys = importance  >= NotificationManager.IMPORTANCE_HIGH
-                && isSystemNotification(e.getSbn());
-
-        return sys;
-    }
-
-    public boolean shouldHide(String key) {
-        if (mRankingMap != null) {
-            getRanking(key, mTmpRanking);
-            return mTmpRanking.isSuspended();
-        }
-        return false;
-    }
-
-    private void updateRankingAndSort(RankingMap rankingMap, String reason) {
-        if (rankingMap != null) {
-            mRankingMap = rankingMap;
-            synchronized (mEntries) {
-                final int len = mEntries.size();
-                for (int i = 0; i < len; i++) {
-                    NotificationEntry entry = mEntries.valueAt(i);
-                    Ranking newRanking = new Ranking();
-                    if (!getRanking(entry.getKey(), newRanking)) {
-                        continue;
-                    }
-                    entry.setRanking(newRanking);
-
-                    final StatusBarNotification oldSbn = entry.getSbn().cloneLight();
-                    final String overrideGroupKey = newRanking.getOverrideGroupKey();
-                    if (!Objects.equals(oldSbn.getOverrideGroupKey(), overrideGroupKey)) {
-                        entry.getSbn().setOverrideGroupKey(overrideGroupKey);
-                        mGroupManager.onEntryUpdated(entry, oldSbn);
-                    }
-                    entry.setIsHighPriority(isHighPriority(entry.getSbn()));
-                }
-            }
-        }
-        filterAndSort(reason);
-    }
-
-    /**
-     * Get the ranking from the current ranking map.
-     *
-     * @param key the key to look up
-     * @param outRanking the ranking to populate
-     *
-     * @return {@code true} if the ranking was properly obtained.
-     */
-    @VisibleForTesting
-    protected boolean getRanking(String key, Ranking outRanking) {
-        return mRankingMap.getRanking(key, outRanking);
-    }
-
-    // TODO: This should not be public. Instead the Environment should notify this class when
-    // anything changed, and this class should call back the UI so it updates itself.
-    /**
-     * Filters and sorts the list of notification entries
-     */
-    public void filterAndSort(String reason) {
-        mNotifLog.log(NotifEvent.FILTER_AND_SORT, reason);
-        mSortedAndFiltered.clear();
-
-        synchronized (mEntries) {
-            final int len = mEntries.size();
-            for (int i = 0; i < len; i++) {
-                NotificationEntry entry = mEntries.valueAt(i);
-
-                if (mNotificationFilter.shouldFilterOut(entry)) {
-                    continue;
-                }
-
-                mSortedAndFiltered.add(entry);
-            }
-        }
-
-        Collections.sort(mSortedAndFiltered, mRankingComparator);
-
-        int bucket = BUCKET_PEOPLE;
-        for (NotificationEntry e : mSortedAndFiltered) {
-            assignBucketForEntry(e);
-            if (e.getBucket() < bucket) {
-                android.util.Log.wtf(TAG, "Detected non-contiguous bucket!");
-            }
-            bucket = e.getBucket();
-        }
-    }
-
-    private void assignBucketForEntry(NotificationEntry e) {
-        boolean isHeadsUp = e.isRowHeadsUp();
-        boolean isMedia = isImportantMedia(e);
-        boolean isSystemMax = isSystemMax(e);
-
-        setBucket(e, isHeadsUp, isMedia, isSystemMax);
-    }
-
-    private void setBucket(
-            NotificationEntry e,
-            boolean isHeadsUp,
-            boolean isMedia,
-            boolean isSystemMax) {
-        if (mUsePeopleFiltering && isPeopleNotification(e)) {
-            e.setBucket(BUCKET_PEOPLE);
-        } else if (isHeadsUp || isMedia || isSystemMax || e.isHighPriority()) {
-            e.setBucket(BUCKET_ALERTING);
-        } else {
-            e.setBucket(BUCKET_SILENT);
-        }
-    }
-
-    private boolean isPeopleNotification(NotificationEntry e) {
-        return mPeopleNotificationIdentifier.isPeopleNotification(e.getSbn());
-    }
-
-    public void dump(PrintWriter pw, String indent) {
-        int filteredLen = mSortedAndFiltered.size();
-        pw.print(indent);
-        pw.println("active notifications: " + filteredLen);
-        int active;
-        for (active = 0; active < filteredLen; active++) {
-            NotificationEntry e = mSortedAndFiltered.get(active);
-            dumpEntry(pw, indent, active, e);
-        }
-        synchronized (mEntries) {
-            int totalLen = mEntries.size();
-            pw.print(indent);
-            pw.println("inactive notifications: " + (totalLen - active));
-            int inactiveCount = 0;
-            for (int i = 0; i < totalLen; i++) {
-                NotificationEntry entry = mEntries.valueAt(i);
-                if (!mSortedAndFiltered.contains(entry)) {
-                    dumpEntry(pw, indent, inactiveCount, entry);
-                    inactiveCount++;
-                }
-            }
-        }
-    }
-
-    private void dumpEntry(PrintWriter pw, String indent, int i, NotificationEntry e) {
-        getRanking(e.getKey(), mTmpRanking);
-        pw.print(indent);
-        pw.println("  [" + i + "] key=" + e.getKey() + " icon=" + e.icon);
-        StatusBarNotification n = e.getSbn();
-        pw.print(indent);
-        pw.println("      pkg=" + n.getPackageName() + " id=" + n.getId() + " importance="
-                + mTmpRanking.getImportance());
-        pw.print(indent);
-        pw.println("      notification=" + n.getNotification());
-    }
-
-    private static boolean isSystemNotification(StatusBarNotification sbn) {
-        String sbnPackage = sbn.getPackageName();
-        return "android".equals(sbnPackage) || "com.android.systemui".equals(sbnPackage);
-    }
-
-    /**
-     * Provides access to keyguard state and user settings dependent data.
-     */
-    public interface KeyguardEnvironment {
-        boolean isDeviceProvisioned();
-        boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index a4c8fc4..3eb55ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -60,6 +60,8 @@
 import com.android.systemui.statusbar.InflationTask;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationGuts;
@@ -84,7 +86,7 @@
  * At the moment, there are many things here that shouldn't be and vice-versa. Hopefully we can
  * clean this up in the future.
  */
-public final class NotificationEntry {
+public final class NotificationEntry extends ListEntry {
 
     private final String mKey;
     private StatusBarNotification mSbn;
@@ -98,6 +100,12 @@
     /** List of lifetime extenders that are extending the lifetime of this notification. */
     final List<NotifLifetimeExtender> mLifetimeExtenders = new ArrayList<>();
 
+    /** If this notification was filtered out, then the filter that did the filtering. */
+    @Nullable NotifFilter mExcludingFilter;
+
+    /** If this was a group child that was promoted to the top level, then who did the promoting. */
+    @Nullable NotifPromoter mNotifPromoter;
+
 
     /*
     * Old members
@@ -113,6 +121,7 @@
     private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
     public CharSequence remoteInputText;
     private final List<Person> mAssociatedPeople = new ArrayList<>();
+    private Notification.BubbleMetadata mBubbleMetadata;
 
     /**
      * If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is
@@ -163,8 +172,8 @@
     public NotificationEntry(
             @NonNull StatusBarNotification sbn,
             @NonNull Ranking ranking) {
-        checkNotNull(sbn);
-        checkNotNull(sbn.getKey());
+        super(checkNotNull(checkNotNull(sbn).getKey()));
+
         checkNotNull(ranking);
 
         mKey = sbn.getKey();
@@ -172,6 +181,11 @@
         setRanking(ranking);
     }
 
+    @Override
+    public NotificationEntry getRepresentativeEntry() {
+        return this;
+    }
+
     /** The key for this notification. Guaranteed to be immutable and unique */
     public String getKey() {
         return mKey;
@@ -199,6 +213,7 @@
         }
 
         mSbn = sbn;
+        mBubbleMetadata = mSbn.getNotification().getBubbleMetadata();
         updatePeopleList();
     }
 
@@ -340,7 +355,33 @@
      * Returns the data needed for a bubble for this notification, if it exists.
      */
     public Notification.BubbleMetadata getBubbleMetadata() {
-        return mSbn.getNotification().getBubbleMetadata();
+        return mBubbleMetadata;
+    }
+
+    /**
+     * Sets bubble metadata for this notification.
+     */
+    public void setBubbleMetadata(Notification.BubbleMetadata metadata) {
+        mBubbleMetadata = metadata;
+    }
+
+    /**
+     * Updates the {@link Notification#FLAG_BUBBLE} flag on this notification to indicate
+     * whether it is a bubble or not. If this entry is set to not bubble, or does not have
+     * the required info to bubble, the flag cannot be set to true.
+     *
+     * @param shouldBubble whether this notification should be flagged as a bubble.
+     * @return true if the value changed.
+     */
+    public boolean setFlagBubble(boolean shouldBubble) {
+        boolean wasBubble = isBubble();
+        if (!shouldBubble) {
+            mSbn.getNotification().flags &= ~FLAG_BUBBLE;
+        } else if (mBubbleMetadata != null && canBubble()) {
+            // wants to be bubble & can bubble, set flag
+            mSbn.getNotification().flags |= FLAG_BUBBLE;
+        }
+        return wasBubble != isBubble();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
new file mode 100644
index 0000000..8bce528
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.app.Notification
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_HIGH
+import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.NotificationManager.IMPORTANCE_MIN
+import android.app.Person
+import android.service.notification.NotificationListenerService.Ranking
+import android.service.notification.NotificationListenerService.RankingMap
+import android.service.notification.StatusBarNotification
+import com.android.internal.annotations.VisibleForTesting
+
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationFilter
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.logging.NotifEvent
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+
+import java.util.Objects
+import java.util.ArrayList
+
+import javax.inject.Inject
+
+import kotlin.Comparator
+
+import dagger.Lazy
+
+private const val TAG = "NotifRankingManager"
+
+/**
+ * NotificationRankingManager is responsible for holding on to the most recent [RankingMap], and
+ * updating SystemUI's set of [NotificationEntry]s with their own ranking. It also sorts and filters
+ * a set of entries (but retains none of them). We also set buckets on the entries here since
+ * bucketing is tied closely to sorting.
+ *
+ * For the curious: this class is one iteration closer to null of what used to be called
+ * NotificationData.java.
+ */
+open class NotificationRankingManager @Inject constructor(
+    private val mediaManagerLazy: Lazy<NotificationMediaManager>,
+    private val groupManager: NotificationGroupManager,
+    private val headsUpManager: HeadsUpManager,
+    private val notifFilter: NotificationFilter,
+    private val notifLog: NotifLog,
+    sectionsFeatureManager: NotificationSectionsFeatureManager
+) {
+
+    var rankingMap: RankingMap? = null
+        protected set
+    private val mediaManager by lazy {
+        mediaManagerLazy.get()
+    }
+    private val usePeopleFiltering: Boolean = sectionsFeatureManager.isFilteringEnabled()
+    private val rankingComparator: Comparator<NotificationEntry> = Comparator { a, b ->
+        val na = a.sbn
+        val nb = b.sbn
+        val aRank = a.ranking.rank
+        val bRank = b.ranking.rank
+
+        val aMedia = isImportantMedia(a)
+        val bMedia = isImportantMedia(b)
+
+        val aSystemMax = a.isSystemMax()
+        val bSystemMax = b.isSystemMax()
+
+        val aHeadsUp = a.isRowHeadsUp
+        val bHeadsUp = b.isRowHeadsUp
+
+        if (usePeopleFiltering && a.isPeopleNotification() != b.isPeopleNotification()) {
+            if (a.isPeopleNotification()) -1 else 1
+        } else if (aHeadsUp != bHeadsUp) {
+            if (aHeadsUp) -1 else 1
+        } else if (aHeadsUp) {
+            // Provide consistent ranking with headsUpManager
+            headsUpManager.compare(a, b)
+        } else if (aMedia != bMedia) {
+            // Upsort current media notification.
+            if (aMedia) -1 else 1
+        } else if (aSystemMax != bSystemMax) {
+            // Upsort PRIORITY_MAX system notifications
+            if (aSystemMax) -1 else 1
+        } else if (a.isHighPriority != b.isHighPriority) {
+            -1 * java.lang.Boolean.compare(a.isHighPriority, b.isHighPriority)
+        } else if (aRank != bRank) {
+            aRank - bRank
+        } else {
+            nb.notification.`when`.compareTo(na.notification.`when`)
+        }
+    }
+
+    private fun isImportantMedia(entry: NotificationEntry): Boolean {
+        val importance = entry.ranking.importance
+        return entry.key == mediaManager.mediaNotificationKey && importance > IMPORTANCE_MIN
+    }
+
+    @VisibleForTesting
+    protected fun isHighPriority(entry: NotificationEntry): Boolean {
+        if (entry.importance >= IMPORTANCE_DEFAULT ||
+                hasHighPriorityCharacteristics(entry)) {
+            return true
+        }
+
+        if (groupManager.isSummaryOfGroup(entry.sbn)) {
+            val logicalChildren = groupManager.getLogicalChildren(entry.sbn)
+            for (child in logicalChildren) {
+                if (isHighPriority(child)) {
+                    return true
+                }
+            }
+        }
+
+        return false
+    }
+
+    private fun hasHighPriorityCharacteristics(entry: NotificationEntry): Boolean {
+        val c = entry.channel
+        val n = entry.sbn.notification
+
+        if (((n.isForegroundService && entry.ranking.importance >= IMPORTANCE_LOW) ||
+            n.hasMediaSession() ||
+            n.hasPerson() ||
+            n.hasStyle(Notification.MessagingStyle::class.java))) {
+            // Users who have long pressed and demoted to silent should not see the notification
+            // in the top section
+            if (c != null && c.hasUserSetImportance()) {
+                return false
+            }
+
+            return true
+        }
+
+        return false
+    }
+
+    fun updateRanking(
+        newRankingMap: RankingMap?,
+        entries: Collection<NotificationEntry>,
+        reason: String
+    ): List<NotificationEntry> {
+        val eSeq = entries.asSequence()
+
+        // TODO: may not be ideal to guard on null here, but this code is implementing exactly what
+        // NotificationData used to do
+        if (newRankingMap != null) {
+            rankingMap = newRankingMap
+            updateRankingForEntries(eSeq)
+        }
+
+        val filtered: Sequence<NotificationEntry>
+        synchronized(this) {
+            filtered = filterAndSortLocked(eSeq, reason)
+        }
+
+        return filtered.toList()
+    }
+
+    /** Uses the [rankingComparator] to sort notifications which aren't filtered */
+    private fun filterAndSortLocked(
+        entries: Sequence<NotificationEntry>,
+        reason: String
+    ): Sequence<NotificationEntry> {
+        notifLog.log(NotifEvent.FILTER_AND_SORT, reason)
+
+        return entries.filter { !notifFilter.shouldFilterOut(it) }
+                .sortedWith(rankingComparator)
+                .map {
+                    assignBucketForEntry(it)
+                    it
+                }
+    }
+
+    private fun assignBucketForEntry(entry: NotificationEntry) {
+        val isHeadsUp = entry.isRowHeadsUp
+        val isMedia = isImportantMedia(entry)
+        val isSystemMax = entry.isSystemMax()
+        setBucket(entry, isHeadsUp, isMedia, isSystemMax)
+    }
+
+    private fun setBucket(
+        entry: NotificationEntry,
+        isHeadsUp: Boolean,
+        isMedia: Boolean,
+        isSystemMax: Boolean
+    ) {
+        if (usePeopleFiltering && entry.hasAssociatedPeople()) {
+            entry.bucket = BUCKET_PEOPLE
+        } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority) {
+            entry.bucket = BUCKET_ALERTING
+        } else {
+            entry.bucket = BUCKET_SILENT
+        }
+    }
+
+    private fun updateRankingForEntries(entries: Sequence<NotificationEntry>) {
+        rankingMap?.let { rankingMap ->
+            synchronized(entries) {
+                entries.forEach { entry ->
+                    val newRanking = Ranking()
+                    if (!rankingMap.getRanking(entry.key, newRanking)) {
+                        return@forEach
+                    }
+                    entry.ranking = newRanking
+
+                    val oldSbn = entry.sbn.cloneLight()
+                    val newOverrideGroupKey = newRanking.overrideGroupKey
+                    if (!Objects.equals(oldSbn.overrideGroupKey, newOverrideGroupKey)) {
+                        entry.sbn.overrideGroupKey = newOverrideGroupKey
+                        // TODO: notify group manager here?
+                        groupManager.onEntryUpdated(entry, oldSbn)
+                    }
+                    entry.setIsHighPriority(isHighPriority(entry))
+                }
+            }
+        }
+    }
+}
+
+// Convenience functions
+private fun NotificationEntry.isSystemMax(): Boolean {
+    return importance >= IMPORTANCE_HIGH && sbn.isSystemNotification()
+}
+
+private fun StatusBarNotification.isSystemNotification(): Boolean {
+    return "android" == packageName || "com.android.systemui" == packageName
+}
+
+private fun Notification.hasPerson(): Boolean {
+    val people: ArrayList<Person> =
+            (extras?.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)) ?: ArrayList()
+    return people.isNotEmpty()
+}
+
+private fun Notification.hasStyle(targetStyleClass: Class<*>): Boolean {
+    return targetStyleClass == notificationStyle
+}
+
+private fun NotificationEntry.isPeopleNotification(): Boolean =
+        sbn.notification.hasStyle(Notification.MessagingStyle::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
index 52fd079..1c0a9d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRowBinderImpl.java
@@ -32,7 +32,6 @@
 import com.android.internal.util.NotificationMessagingUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.UiOffloadThread;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
@@ -61,7 +60,6 @@
             Dependency.get(NotificationGroupManager.class);
     private final NotificationGutsManager mGutsManager =
             Dependency.get(NotificationGutsManager.class);
-    private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class);
     private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
             Dependency.get(NotificationInterruptionStateProvider.class);
 
@@ -81,16 +79,20 @@
     private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
     private BindRowCallback mBindRowCallback;
     private NotificationClicker mNotificationClicker;
-    private final NotificationLogger mNotificationLogger = Dependency.get(NotificationLogger.class);
+    private final NotificationLogger mNotificationLogger;
 
-    public NotificationRowBinderImpl(Context context, boolean allowLongPress,
+    public NotificationRowBinderImpl(
+            Context context,
+            boolean allowLongPress,
             KeyguardBypassController keyguardBypassController,
-            StatusBarStateController statusBarStateController) {
+            StatusBarStateController statusBarStateController,
+            NotificationLogger logger) {
         mContext = context;
         mMessagingUtil = new NotificationMessagingUtil(context);
         mAllowLongPress = allowLongPress;
         mKeyguardBypassController = keyguardBypassController;
         mStatusBarStateController = statusBarStateController;
+        mNotificationLogger = logger;
     }
 
     private NotificationRemoteInputManager getRemoteInputManager() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java
new file mode 100644
index 0000000..986ee17
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/FakePipelineConsumer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.init;
+
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.notification.collection.GroupEntry;
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Temporary class that tracks the result of the list builder and dumps it to text when requested.
+ *
+ * Eventually, this will be something that hands off the result of the pipeline to the View layer.
+ */
+public class FakePipelineConsumer implements Dumpable {
+    private List<ListEntry> mEntries = Collections.emptyList();
+
+    /** Attach the consumer to the pipeline. */
+    public void attach(NotifListBuilderImpl listBuilder) {
+        listBuilder.setOnRenderListListener(this::onBuildComplete);
+    }
+
+    private void onBuildComplete(List<ListEntry> entries) {
+        mEntries = entries;
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println();
+        pw.println("Active notif tree:");
+        for (int i = 0; i < mEntries.size(); i++) {
+            ListEntry entry = mEntries.get(i);
+            if (entry instanceof GroupEntry) {
+                GroupEntry ge = (GroupEntry) entry;
+                pw.println(dumpGroup(ge, "", i));
+
+                pw.println(dumpEntry(ge.getSummary(), INDENT, -1));
+                for (int j = 0; j < ge.getChildren().size(); j++) {
+                    pw.println(dumpEntry(ge.getChildren().get(j), INDENT, j));
+                }
+            } else {
+                pw.println(dumpEntry(entry.getRepresentativeEntry(), "", i));
+            }
+        }
+    }
+
+    private String dumpGroup(GroupEntry entry, String indent, int index) {
+        return String.format(
+                "%s[%d] %s (group)",
+                indent,
+                index,
+                entry.getKey());
+    }
+
+    private String dumpEntry(NotificationEntry entry, String indent, int index) {
+        return String.format(
+                "%s[%s] %s (channel=%s)",
+                indent,
+                index == -1 ? "*" : Integer.toString(index),
+                entry.getKey(),
+                entry.getChannel() != null ? entry.getChannel().getId() : "");
+    }
+
+    private static final String INDENT = "   ";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
new file mode 100644
index 0000000..3b3e7e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/init/NewNotifPipeline.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.init;
+
+import android.util.Log;
+
+import com.android.systemui.DumpController;
+import com.android.systemui.Dumpable;
+import com.android.systemui.statusbar.NotificationListener;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+/**
+ * Initialization code for the new notification pipeline.
+ */
+@Singleton
+public class NewNotifPipeline implements Dumpable {
+    private final NotifCollection mNotifCollection;
+    private final NotifListBuilderImpl mNotifPipeline;
+    private final DumpController mDumpController;
+
+    private final FakePipelineConsumer mFakePipelineConsumer = new FakePipelineConsumer();
+
+    @Inject
+    public NewNotifPipeline(
+            NotifCollection notifCollection,
+            NotifListBuilderImpl notifPipeline,
+            DumpController dumpController) {
+        mNotifCollection = notifCollection;
+        mNotifPipeline = notifPipeline;
+        mDumpController = dumpController;
+    }
+
+    /** Hooks the new pipeline up to NotificationManager */
+    public void initialize(
+            NotificationListener notificationService) {
+        mFakePipelineConsumer.attach(mNotifPipeline);
+        mNotifPipeline.attach(mNotifCollection);
+        mNotifCollection.attach(notificationService);
+
+        Log.d(TAG, "Notif pipeline initialized");
+
+        mDumpController.registerDumpable("NotifPipeline", this);
+    }
+
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mFakePipelineConsumer.dump(fd, pw, args);
+    }
+
+    private static final String TAG = "NewNotifPipeline";
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
new file mode 100644
index 0000000..15d3b92
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/NotifListBuilder.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.NotifCollection;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+
+import java.util.List;
+
+/**
+ * The system that constructs the current "notification list", the list of notifications that are
+ * currently being displayed to the user.
+ *
+ * The pipeline proceeds through a series of stages in order to produce the final list (see below).
+ * Each stage exposes hooks and listeners for other code to participate.
+ *
+ * This list differs from the canonical one we receive from system server in a few ways:
+ * - Filtered: Some notifications are filtered out. For example, we filter out notifications whose
+ *   views haven't been inflated yet. We also filter out some notifications if we're on the lock
+ *   screen. To participate, see {@link #addFilter(NotifFilter)}.
+ * - Grouped: Notifications that are part of the same group are clustered together into a single
+ *   GroupEntry. These groups are then transformed in order to remove children or completely split
+ *   them apart. To participate, see {@link #addPromoter(NotifPromoter)}.
+ * - Sorted: All top-level notifications are sorted. To participate, see
+ *   {@link #setSectionsProvider(SectionsProvider)} and {@link #setComparators(List)}
+ *
+ * The exact order of all hooks is as follows:
+ *  0. Collection listeners are fired (see {@link NotifCollection}).
+ *  1. NotifFilters are called on each notification currently in NotifCollection.
+ *  2. Initial grouping is performed (NotificationEntries will have their parents set
+ *     appropriately).
+ *  3. OnBeforeTransformGroupListeners are fired
+ *  4. NotifPromoters are called on each notification with a parent
+ *  5. OnBeforeSortListeners are fired
+ *  6. SectionsProvider is called on each top-level entry in the list
+ *  7. The top-level entries are sorted using the provided NotifComparators (plus some additional
+ *     built-in logic).
+ *  8. OnBeforeRenderListListeners are fired
+ *  9. The list is handed off to the view layer to be rendered.
+ */
+public interface NotifListBuilder {
+
+    /**
+     * Registers a filter with the pipeline. Filters are called on each notification in the order
+     * that they were registered. If any filter returns true, the notification is removed from the
+     * pipeline (and no other filters are called on that notif).
+     */
+    void addFilter(NotifFilter filter);
+
+    /**
+     * Registers a promoter with the pipeline. Promoters are able to promote child notifications to
+     * top-level, i.e. move a notification that would be a child of a group and make it appear
+     * ungrouped. Promoters are called on each child notification in the order that they are
+     * registered. If any promoter returns true, the notification is removed from the group (and no
+     * other promoters are called on it).
+     */
+    void addPromoter(NotifPromoter promoter);
+
+    /**
+     * Assigns sections to each top-level entry, where a section is simply an integer. Sections are
+     * the primary metric by which top-level entries are sorted; NotifComparators are only consulted
+     * when two entries are in the same section. The pipeline doesn't assign any particular meaning
+     * to section IDs -- from it's perspective they're just numbers and it sorts them by a simple
+     * numerical comparison.
+     */
+    void setSectionsProvider(SectionsProvider provider);
+
+    /**
+     * Comparators that are used to sort top-level entries that share the same section. The
+     * comparators are executed in order until one of them returns a non-zero result. If all return
+     * zero, the pipeline falls back to sorting by rank (and, failing that, Notification.when).
+     */
+    void setComparators(List<NotifComparator> comparators);
+
+    /**
+     * Called after notifications have been filtered and after the initial grouping has been
+     * performed but before NotifPromoters have had a chance to promote children out of groups.
+     */
+    void addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener listener);
+
+    /**
+     * Called after notifs have been filtered and groups have been determined but before sections
+     * have been determined or the notifs have been sorted.
+     */
+    void addOnBeforeSortListener(OnBeforeSortListener listener);
+
+    /**
+     * Called at the end of the pipeline after the notif list has been finalized but before it has
+     * been handed off to the view layer.
+     */
+    void addOnBeforeRenderListListener(OnBeforeRenderListListener listener);
+
+    /**
+     * Returns a read-only view in to the current notification list. If this method is called
+     * during pipeline execution it will return the current state of the list, which will likely
+     * be only partially-generated.
+     */
+    List<ListEntry> getActiveNotifs();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java
new file mode 100644
index 0000000..f6ca12d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeRenderListListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+
+import java.util.List;
+
+/** See {@link NotifListBuilder#addOnBeforeRenderListListener(OnBeforeRenderListListener)} */
+public interface OnBeforeRenderListListener {
+    /**
+     * Called at the end of the pipeline after the notif list has been finalized but before it has
+     * been handed off to the view layer.
+     *
+     * @param entries The current list of top-level entries. Note that this is a live view into the
+     *                current list and will change whenever the pipeline is rerun.
+     */
+    void onBeforeRenderList(List<ListEntry> entries);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java
new file mode 100644
index 0000000..7be7ac0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeSortListener.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+
+import java.util.List;
+
+/** See {@link NotifListBuilder#addOnBeforeSortListener(OnBeforeSortListener)} */
+public interface OnBeforeSortListener {
+    /**
+     * Called after the notif list has been filtered and grouped but before sections have been
+     * determined or sorting has taken place.
+     *
+     * @param entries The current list of top-level entries. Note that this is a live view into the
+     *                current list and will change whenever the pipeline is rerun.
+     */
+    void onBeforeSort(List<ListEntry> entries);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
new file mode 100644
index 0000000..170ff48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/OnBeforeTransformGroupsListener.java
@@ -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 com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+
+import java.util.List;
+
+/**
+ * See
+ * {@link NotifListBuilder#addOnBeforeTransformGroupsListener(OnBeforeTransformGroupsListener)}
+ */
+public interface OnBeforeTransformGroupsListener {
+    /**
+     * Called after notifs have been filtered and grouped but before {@link NotifPromoter}s have
+     * been called.
+     *
+     * @param list The current filtered and grouped list of (top-level) entries. Note that this is
+     *             a live view into the current notif list and will change as the list moves through
+     *             the pipeline.
+     * @param newlyVisibleEntries The list of all entries (both top-level and children) who have
+     *                            been added to the list for the first time.
+     */
+    void onBeforeTransformGroups(List<ListEntry> list, List<ListEntry> newlyVisibleEntries);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
new file mode 100644
index 0000000..ad4bbd9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder;
+
+import android.annotation.IntDef;
+
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used by {@link NotifListBuilderImpl} to track its internal state machine.
+ */
+public class PipelineState {
+
+    private @StateName int mState = STATE_IDLE;
+
+    /** Returns true if the current state matches <code>state</code> */
+    public boolean is(@StateName int state) {
+        return state == mState;
+    }
+
+    public @StateName int getState() {
+        return mState;
+    }
+
+    public void setState(@StateName int state) {
+        mState = state;
+    }
+
+    /**
+     * Increments the state from <code>(to - 1)</code> to <code>to</code>. If the current state
+     * isn't <code>(to - 1)</code>, throws an exception.
+     */
+    public void incrementTo(@StateName int to) {
+        if (mState != to - 1) {
+            throw new IllegalStateException(
+                    "Cannot increment from state " + mState + " to state " + to);
+        }
+        mState = to;
+    }
+
+    /**
+     * Throws an exception if the current state is not <code>state</code>.
+     */
+    public void requireState(@StateName int state) {
+        if (state != mState) {
+            throw new IllegalStateException(
+                    "Required state is <" + state + " but actual state is " + mState);
+        }
+    }
+
+    /**
+     * Throws an exception if the current state is >= <code>state</code>.
+     */
+    public void requireIsBefore(@StateName int state) {
+        if (mState >= state) {
+            throw new IllegalStateException(
+                    "Required state is <" + state + " but actual state is " + mState);
+        }
+    }
+
+    public static final int STATE_IDLE = 0;
+    public static final int STATE_BUILD_PENDING = 1;
+    public static final int STATE_BUILD_STARTED = 2;
+    public static final int STATE_FILTERING = 3;
+    public static final int STATE_TRANSFORMING = 4;
+    public static final int STATE_SORTING = 5;
+    public static final int STATE_FINALIZING = 6;
+
+    @IntDef(prefix = { "STATE_" }, value = {
+            STATE_IDLE,
+            STATE_BUILD_PENDING,
+            STATE_BUILD_STARTED,
+            STATE_FILTERING,
+            STATE_TRANSFORMING,
+            STATE_SORTING,
+            STATE_FINALIZING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StateName {}
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
new file mode 100644
index 0000000..a191c83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifComparator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Pluggable for participating in notif sorting. See {@link NotifListBuilder#setComparators(List)}.
+ */
+public abstract class NotifComparator
+        extends Pluggable<NotifComparator>
+        implements Comparator<ListEntry> {
+
+    protected NotifComparator(String name) {
+        super(name);
+    }
+
+    /**
+     * Compare two ListEntries. Note that these might be either NotificationEntries or GroupEntries.
+     *
+     * @return a negative integer, zero, or a positive integer as the first argument is less than
+     *      equal to, or greater than the second (same as standard Comparator<> interface).
+     */
+    public abstract int compare(ListEntry o1, ListEntry o2);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
new file mode 100644
index 0000000..685eac8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifFilter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+
+/**
+ * Pluggable for participating in notif filtering. See
+ * {@link NotifListBuilder#addFilter(NotifFilter)}.
+ */
+public abstract class NotifFilter extends Pluggable<NotifFilter> {
+    protected NotifFilter(String name) {
+        super(name);
+    }
+
+    /**
+     * If returns true, this notification will not be included in the final list displayed to the
+     * user. Filtering is performed on each active notification every time the pipeline is run.
+     * This doesn't necessarily mean that your filter will get called on every notification,
+     * however. If another filter returns true before yours, we'll skip straight to the next notif.
+     *
+     * @param entry The entry in question
+     * @param now A timestamp in SystemClock.uptimeMillis that represents "now" for the purposes of
+     *            pipeline execution. This value will be the same for all pluggable calls made
+     *            during this pipeline run, giving pluggables a stable concept of "now" to compare
+     *            various entries against.
+     * @return True if the notif should be removed from the list
+     */
+    public abstract boolean shouldFilterOut(NotificationEntry entry, long now);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java
new file mode 100644
index 0000000..84e16f4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/NotifPromoter.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+
+/**
+ *  Pluggable for participating in notif promotion. Notif promoters can upgrade notifications
+ *  from being children of a group to top-level notifications. See
+ *  {@link NotifListBuilder#addPromoter(NotifPromoter)}.
+ */
+public abstract class NotifPromoter extends Pluggable<NotifPromoter> {
+    protected NotifPromoter(String name) {
+        super(name);
+    }
+
+    /**
+     * If true, the child will be removed from its parent and placed at the top level of the notif
+     * list. By the time this method is called, child.getParent() has been set, so you can
+     * examine it (or any other entries in the notif list) for extra information.
+     *
+     * This method is only called on notifs that are currently children of groups. This doesn't
+     * necessarily mean that your promoter will get called on every child notification, however. If
+     * another promoter returns true before yours, we'll skip straight to the next notif.
+     */
+    public abstract boolean shouldPromoteToTopLevel(NotificationEntry child);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.java
new file mode 100644
index 0000000..f9ce197
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/Pluggable.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.statusbar.notification.collection.listbuilder.pluggable;
+
+import android.annotation.Nullable;
+
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifListBuilder;
+
+/**
+ * Generic superclass for chunks of code that can plug into the {@link NotifListBuilder}.
+ *
+ * A pluggable is fundamentally three things:
+ * 1. A name (for debugging purposes)
+ * 2. The functionality that the pluggable provides to the pipeline (this is determined by the
+ *    subclass).
+ * 3. A way for the pluggable to inform the pipeline that its state has changed and the pipeline
+ *    should be rerun (in this case, the invalidate() method).
+ *
+ * @param <This> The type of the subclass. Subclasses should bind their own type here.
+ */
+public abstract class Pluggable<This> {
+    private final String mName;
+    @Nullable private PluggableListener<This> mListener;
+
+    Pluggable(String name) {
+        mName = name;
+    }
+
+    public final String getName() {
+        return mName;
+    }
+
+    /**
+     * Call this method when something has caused this pluggable's behavior to change. The pipeline
+     * will be re-run.
+     */
+    public final void invalidateList() {
+        if (mListener != null) {
+            mListener.onPluggableInvalidated((This) this);
+        }
+    }
+
+    /** Set a listener to be notified when a pluggable is invalidated. */
+    public void setInvalidationListener(PluggableListener<This> listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Listener interface for when pluggables are invalidated.
+     *
+     * @param <T> The type of pluggable that is being listened to.
+     */
+    public interface PluggableListener<T> {
+        /** Called whenever {@link #invalidateList()} is called on this pluggable. */
+        void onPluggableInvalidated(T pluggable);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/SectionsProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/SectionsProvider.java
new file mode 100644
index 0000000..11ea850
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/pluggable/SectionsProvider.java
@@ -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 com.android.systemui.statusbar.notification.collection.listbuilder.pluggable;
+
+import com.android.systemui.statusbar.notification.collection.ListEntry;
+
+/**
+ * Interface for sorting notifications into "sections", such as a heads-upping section, people
+ * section, alerting section, silent section, etc.
+ */
+public abstract class SectionsProvider extends Pluggable<SectionsProvider> {
+
+    protected SectionsProvider(String name) {
+        super(name);
+    }
+
+    /**
+     * Returns the section that this entry belongs to. A section can be any non-negative integer.
+     * When entries are sorted, they are first sorted by section and then by any remainining
+     * comparators.
+     */
+    public abstract int getSection(ListEntry entry);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index b7f408e..77ccf19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -43,9 +43,9 @@
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.List;
 import java.util.Map;
 
 import javax.inject.Inject;
@@ -113,7 +113,7 @@
         public void run() {
             mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
 
-            // 1. Loop over mNotificationData entries:
+            // 1. Loop over active entries:
             //   A. Keep list of visible notifications.
             //   B. Keep list of previously hidden, now visible notifications.
             // 2. Compute no-longer visible notifications by removing currently
@@ -121,8 +121,7 @@
             //    notifications.
             // 3. Report newly visible and no-longer visible notifications.
             // 4. Keep currently visible notifications for next report.
-            ArrayList<NotificationEntry> activeNotifications = mEntryManager
-                    .getNotificationData().getActiveNotifications();
+            List<NotificationEntry> activeNotifications = mEntryManager.getVisibleNotifications();
             int N = activeNotifications.size();
             for (int i = 0; i < N; i++) {
                 NotificationEntry entry = activeNotifications.get(i);
@@ -220,8 +219,8 @@
             }
 
             @Override
-            public void onEntryReinflated(NotificationEntry entry) {
-                mExpansionStateLogger.onEntryReinflated(entry.getKey());
+            public void onPreEntryUpdated(NotificationEntry entry) {
+                mExpansionStateLogger.onEntryUpdated(entry.getKey());
             }
 
             @Override
@@ -403,7 +402,7 @@
      */
     public void onExpansionChanged(String key, boolean isUserAction, boolean isExpanded) {
         NotificationVisibility.NotificationLocation location =
-                getNotificationLocation(mEntryManager.getNotificationData().get(key));
+                getNotificationLocation(mEntryManager.getActiveNotificationUnfiltered(key));
         mExpansionStateLogger.onExpansionChanged(key, isUserAction, isExpanded, location);
     }
 
@@ -480,7 +479,7 @@
         }
 
         @VisibleForTesting
-        void onEntryReinflated(String key) {
+        void onEntryUpdated(String key) {
             // When the notification is updated, we should consider the notification as not
             // yet logged.
             mLoggedExpansionState.remove(key);
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 1de2cbb..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
@@ -41,7 +41,6 @@
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
@@ -63,6 +62,8 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  * Handles various NotificationGuts related tasks, such as binding guts to a row, opening and
  * closing guts, and keeping track of the currently exposed notification guts.
@@ -99,15 +100,15 @@
     @VisibleForTesting
     protected String mKeyToRemoveOnGutsClosed;
 
-    private StatusBar mStatusBar;
+    private final Lazy<StatusBar> mStatusBarLazy;
     private Runnable mOpenRunnable;
 
     @Inject
-    public NotificationGutsManager(
-            Context context,
-            VisualStabilityManager visualStabilityManager) {
+    public NotificationGutsManager(Context context, VisualStabilityManager visualStabilityManager,
+            Lazy<StatusBar> statusBarLazy) {
         mContext = context;
         mVisualStabilityManager = visualStabilityManager;
+        mStatusBarLazy = statusBarLazy;
         mAccessibilityManager = (AccessibilityManager)
                 mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
     }
@@ -119,7 +120,6 @@
         mListContainer = listContainer;
         mCheckSaveListener = checkSave;
         mOnSettingsClickListener = onSettingsClick;
-        mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
     }
 
     public void setNotificationActivityStarter(
@@ -319,7 +319,7 @@
                 packageName,
                 row.getEntry().getChannel(),
                 row.getUniqueChannels(),
-                sbn,
+                row.getEntry(),
                 mCheckSaveListener,
                 onSettingsClick,
                 onAppSettingsClick,
@@ -392,7 +392,7 @@
             Runnable r = () -> Dependency.get(Dependency.MAIN_HANDLER).post(
                     () -> openGutsInternal(view, x, y, menuItem));
 
-            mStatusBar.executeRunnableDismissingKeyguard(
+            mStatusBarLazy.get().executeRunnableDismissingKeyguard(
                     r,
                     null /* cancelAction */,
                     false /* dismissShade */,
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..516d649 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
@@ -167,12 +167,6 @@
         mContext = ctx;
         mMediaManager = Dependency.get(NotificationMediaManager.class);
         mMetricsLogger = Dependency.get(MetricsLogger.class);
-
-        if (mView instanceof MediaNotificationView) {
-            MediaNotificationView mediaView = (MediaNotificationView) mView;
-            mediaView.addVisibilityListener(mVisibilityListener);
-            mView.addOnAttachStateChangeListener(mAttachStateListener);
-        }
     }
 
     private void resolveViews() {
@@ -183,6 +177,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 +186,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,
@@ -210,13 +207,13 @@
         }
 
         // Check for existing media controller and clean up / create as necessary
-        boolean controllerUpdated = false;
+        boolean shouldUpdateListeners = false;
         if (mMediaController == null || !mMediaController.getSessionToken().equals(token)) {
             if (mMediaController != null) {
                 mMediaController.unregisterCallback(mMediaCallback);
             }
             mMediaController = new MediaController(mContext, token);
-            controllerUpdated = true;
+            shouldUpdateListeners = true;
         }
 
         mMediaMetadata = mMediaController.getMetadata();
@@ -228,7 +225,7 @@
                     mSeekBarView.setVisibility(View.GONE);
                     mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
                     clearTimer();
-                } else if (mSeekBarView == null && controllerUpdated) {
+                } else if (mSeekBarView == null && shouldUpdateListeners) {
                     // Only log if the controller changed, otherwise we would log multiple times for
                     // the same notification when user pauses/resumes
                     mMetricsLogger.write(newLog(MetricsEvent.TYPE_CLOSE));
@@ -258,6 +255,16 @@
             mSeekBarElapsedTime = mSeekBarView.findViewById(R.id.notification_media_elapsed_time);
             mSeekBarTotalTime = mSeekBarView.findViewById(R.id.notification_media_total_time);
 
+            shouldUpdateListeners = true;
+        }
+
+        if (shouldUpdateListeners) {
+            if (mView instanceof MediaNotificationView) {
+                MediaNotificationView mediaView = (MediaNotificationView) mView;
+                mediaView.addVisibilityListener(mVisibilityListener);
+                mView.addOnAttachStateChangeListener(mAttachStateListener);
+            }
+
             if (mSeekBarTimer == null) {
                 if (mMediaController != null && canSeekMedia(mMediaController.getPlaybackState())) {
                     // Log initial state, since it will not be updated
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 8d50f58..462fa59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -608,10 +608,10 @@
 
         mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
             @Override
-            public void onPostEntryUpdated(NotificationEntry entry) {
-                if (!entry.getSbn().isClearable()) {
-                    // The user may have performed a dismiss action on the notification, since it's
-                    // not clearable we should snap it back.
+            public void onPreEntryUpdated(NotificationEntry entry) {
+                if (entry.rowExists() && !entry.getSbn().isClearable()) {
+                    // If the row already exists, the user may have performed a dismiss action on
+                    // the notification. Since it's not clearable we should snap it back.
                     snapViewIfNeeded(entry);
                 }
             }
@@ -696,8 +696,7 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void updateFooter() {
         boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
-        boolean showFooterView = (showDismissView ||
-                mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
+        boolean showFooterView = (showDismissView || mEntryManager.hasActiveNotifications())
                 && mStatusBarState != StatusBarState.KEYGUARD
                 && !mRemoteInputManager.getController().isRemoteInputActive();
 
@@ -5787,11 +5786,6 @@
   }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    public boolean hasActiveNotifications() {
-        return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
-    }
-
-    @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void updateSpeedBumpIndex() {
         int speedBumpIndex = 0;
         int currentIndex = 0;
@@ -6400,7 +6394,7 @@
         @Override
         public boolean onDraggedDown(View startingChild, int dragLengthY) {
             if (mStatusBarState == StatusBarState.KEYGUARD
-                    && hasActiveNotifications()) {
+                    && mEntryManager.hasActiveNotifications()) {
                 mLockscreenGestureLogger.write(
                         MetricsEvent.ACTION_LS_SHADE,
                         (int) (dragLengthY / mDisplayMetrics.density),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 0092cc9..8b31da4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -32,7 +32,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.StatusBarState;
@@ -82,7 +81,7 @@
         mKeyguardStateController = Dependency.get(KeyguardStateController.class);
         mNetworkController = Dependency.get(NetworkController.class);
         mStatusBarStateController = Dependency.get(StatusBarStateController.class);
-        mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
+        mStatusBarComponent = Dependency.get(StatusBar.class);
         mCommandQueue = Dependency.get(CommandQueue.class);
     }
 
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 2854355..6aee194 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -81,7 +81,7 @@
     private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     private BiometricUnlockController mBiometricUnlockController;
     private final KeyguardViewMediator mKeyguardViewMediator;
-    private final AssistManager mAssistManager;
+    private final Lazy<AssistManager> mAssistManagerLazy;
     private final DozeScrimController mDozeScrimController;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final VisualStabilityManager mVisualStabilityManager;
@@ -105,7 +105,7 @@
             ScrimController scrimController,
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             KeyguardViewMediator keyguardViewMediator,
-            AssistManager assistManager,
+            Lazy<AssistManager> assistManagerLazy,
             DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
             VisualStabilityManager visualStabilityManager,
             PulseExpansionHandler pulseExpansionHandler,
@@ -122,7 +122,7 @@
         mScrimController = scrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
         mKeyguardViewMediator = keyguardViewMediator;
-        mAssistManager = assistManager;
+        mAssistManagerLazy = assistManagerLazy;
         mDozeScrimController = dozeScrimController;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mVisualStabilityManager = visualStabilityManager;
@@ -225,7 +225,7 @@
         if (reason == DozeEvent.PULSE_REASON_SENSOR_LONG_PRESS) {
             mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                                  "com.android.systemui:LONG_PRESS");
-            mAssistManager.startAssist(new Bundle());
+            mAssistManagerLazy.get().startAssist(new Bundle());
             return;
         }
 
@@ -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/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 4e06c84..6ac6d35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -52,13 +52,9 @@
 import java.util.HashSet;
 import java.util.Stack;
 
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
 /**
  * A implementation of HeadsUpManager for phone and car.
  */
-@Singleton
 public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
         VisualStabilityManager.Callback, OnHeadsUpChangedListener,
         ConfigurationController.ConfigurationListener, StateListener {
@@ -113,7 +109,6 @@
     ///////////////////////////////////////////////////////////////////////////////////////////////
     //  Constructor:
 
-    @Inject
     public HeadsUpManagerPhone(@NonNull final Context context,
             StatusBarStateController statusBarStateController,
             KeyguardBypassController bypassController) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
index 2c931ae..e763496 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardEnvironmentImpl.java
@@ -22,7 +22,7 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
 import javax.inject.Inject;
@@ -42,12 +42,12 @@
     public KeyguardEnvironmentImpl() {
     }
 
-    @Override  // NotificationData.KeyguardEnvironment
+    @Override  // NotificationEntryManager.KeyguardEnvironment
     public boolean isDeviceProvisioned() {
         return mDeviceProvisionedController.isDeviceProvisioned();
     }
 
-    @Override  // NotificationData.KeyguardEnvironment
+    @Override  // NotificationEntryManager.KeyguardEnvironment
     public boolean isNotificationForCurrentProfiles(StatusBarNotification n) {
         final int notificationUserId = n.getUserId();
         if (DEBUG && MULTIUSER_DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
index 93887a6..5703f06 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
@@ -97,7 +97,7 @@
     }
 
     private boolean hasActiveNotifications() {
-        return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+        return mEntryManager.hasActiveNotifications();
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 4927ec8..60589843 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -39,7 +39,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.telephony.IccCardConstants;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.Dependency;
@@ -154,8 +153,7 @@
     private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onSimStateChanged(int subId, int slotId,
-                        IccCardConstants.State simState) {
+                public void onSimStateChanged(int subId, int slotId, int simState) {
                     mSimLocked = mKeyguardUpdateMonitor.isSimPinSecure();
                     update();
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 1c46cf8..2674db4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -91,7 +91,6 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -123,6 +122,8 @@
 
 import javax.inject.Inject;
 
+import dagger.Lazy;
+
 /**
  * Fragment containing the NavigationBarFragment. Contains logic for what happens
  * on clicks and view states of the nav bar.
@@ -162,6 +163,8 @@
 
     private int mDisabledFlags1;
     private int mDisabledFlags2;
+    private final Lazy<StatusBar> mStatusBarLazy;
+    private Recents mRecents;
     private StatusBar mStatusBar;
     private final Divider mDivider;
     private final Optional<Recents> mRecentsOptional;
@@ -213,7 +216,7 @@
             mNavigationBarView.getRotationButtonController().setRotateSuggestionButtonState(false);
 
             // Hide the notifications panel when quick step starts
-            mStatusBar.collapsePanel(true /* animate */);
+            mStatusBarLazy.get().collapsePanel(true /* animate */);
         }
 
         @Override
@@ -267,15 +270,15 @@
             StatusBarStateController statusBarStateController,
             SysUiState sysUiFlagsContainer,
             BroadcastDispatcher broadcastDispatcher,
-            CommandQueue commandQueue,
-            Divider divider,
-            Optional<Recents> recentsOptional) {
+            CommandQueue commandQueue, Divider divider,
+            Optional<Recents> recentsOptional, Lazy<StatusBar> statusBarLazy) {
         mAccessibilityManagerWrapper = accessibilityManagerWrapper;
         mDeviceProvisionedController = deviceProvisionedController;
         mStatusBarStateController = statusBarStateController;
         mMetricsLogger = metricsLogger;
         mAssistManager = assistManager;
         mSysUiFlagsContainer = sysUiFlagsContainer;
+        mStatusBarLazy = statusBarLazy;
         mAssistantAvailable = mAssistManager.getAssistInfoForUser(UserHandle.USER_CURRENT) != null;
         mOverviewProxyService = overviewProxyService;
         mNavigationModeController = navigationModeController;
@@ -292,7 +295,6 @@
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mCommandQueue.observe(getLifecycle(), this);
-        mStatusBar = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
         mWindowManager = getContext().getSystemService(WindowManager.class);
         mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
         mContentResolver = getContext().getContentResolver();
@@ -343,7 +345,7 @@
             mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         }
 
-        mNavigationBarView.setComponents(mStatusBar.getPanel(), mAssistManager);
+        mNavigationBarView.setComponents(mStatusBarLazy.get().getPanel(), mAssistManager);
         mNavigationBarView.setDisabledFlags(mDisabledFlags1);
         mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
         mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
@@ -750,7 +752,7 @@
                 TelecomManager telecomManager =
                         getContext().getSystemService(TelecomManager.class);
                 if (telecomManager != null && telecomManager.isRinging()) {
-                    if (mStatusBar.isKeyguardShowing()) {
+                    if (mStatusBarLazy.get().isKeyguardShowing()) {
                         Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
                                 "No heads up");
                         mHomeBlockedThisTouch = true;
@@ -760,14 +762,14 @@
                 break;
             case MotionEvent.ACTION_UP:
             case MotionEvent.ACTION_CANCEL:
-                mStatusBar.awakenDreams();
+                mStatusBarLazy.get().awakenDreams();
                 break;
         }
         return false;
     }
 
     private void onVerticalChanged(boolean isVertical) {
-        mStatusBar.setQsScrimEnabled(!isVertical);
+        mStatusBarLazy.get().setQsScrimEnabled(!isVertical);
     }
 
     private boolean onNavigationTouch(View v, MotionEvent event) {
@@ -789,7 +791,7 @@
         args.putInt(
                 AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS);
         mAssistManager.startAssist(args);
-        mStatusBar.awakenDreams();
+        mStatusBarLazy.get().awakenDreams();
 
         if (mNavigationBarView != null) {
             mNavigationBarView.abortCurrentGesture();
@@ -818,7 +820,7 @@
             LatencyTracker.getInstance(getContext()).onActionStart(
                     LatencyTracker.ACTION_TOGGLE_RECENTS);
         }
-        mStatusBar.awakenDreams();
+        mStatusBarLazy.get().awakenDreams();
         mCommandQueue.toggleRecentApps();
     }
 
@@ -916,7 +918,7 @@
             return false;
         }
 
-        return mStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
+        return mStatusBarLazy.get().toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
                 MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
     }
 
@@ -1039,7 +1041,7 @@
     private void checkBarModes() {
         // We only have status bar on default display now.
         if (mIsOnDefaultDisplay) {
-            mStatusBar.checkBarModes();
+            mStatusBarLazy.get().checkBarModes();
         } else {
             checkNavBarModes();
         }
@@ -1053,7 +1055,7 @@
      * Checks current navigation bar mode and make transitions.
      */
     public void checkNavBarModes() {
-        final boolean anim = mStatusBar.isDeviceInteractive()
+        final boolean anim = mStatusBarLazy.get().isDeviceInteractive()
                 && mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
         mNavigationBarView.getBarTransitions().transitionTo(mNavigationBarMode, anim);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 159a829..d3c7940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -66,7 +66,6 @@
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.assist.AssistHandleViewController;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.model.SysUiState;
@@ -214,31 +213,32 @@
         }
     };
 
-    private final AccessibilityDelegate mQuickStepAccessibilityDelegate
-            = new AccessibilityDelegate() {
-        private AccessibilityAction mToggleOverviewAction;
+    private final AccessibilityDelegate mQuickStepAccessibilityDelegate =
+            new AccessibilityDelegate() {
+                private AccessibilityAction mToggleOverviewAction;
 
-        @Override
-        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
-            super.onInitializeAccessibilityNodeInfo(host, info);
-            if (mToggleOverviewAction == null) {
-                mToggleOverviewAction = new AccessibilityAction(R.id.action_toggle_overview,
-                    getContext().getString(R.string.quick_step_accessibility_toggle_overview));
-            }
-            info.addAction(mToggleOverviewAction);
-        }
+                @Override
+                public void onInitializeAccessibilityNodeInfo(View host,
+                        AccessibilityNodeInfo info) {
+                    super.onInitializeAccessibilityNodeInfo(host, info);
+                    if (mToggleOverviewAction == null) {
+                        mToggleOverviewAction = new AccessibilityAction(
+                                R.id.action_toggle_overview, getContext().getString(
+                                R.string.quick_step_accessibility_toggle_overview));
+                    }
+                    info.addAction(mToggleOverviewAction);
+                }
 
-        @Override
-        public boolean performAccessibilityAction(View host, int action, Bundle args) {
-            if (action == R.id.action_toggle_overview) {
-                SysUiServiceProvider.getComponent(getContext(), Recents.class)
-                        .toggleRecentApps();
-            } else {
-                return super.performAccessibilityAction(host, action, args);
-            }
-            return true;
-        }
-    };
+                @Override
+                public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                    if (action == R.id.action_toggle_overview) {
+                        Dependency.get(Recents.class).toggleRecentApps();
+                    } else {
+                        return super.performAccessibilityAction(host, action, args);
+                    }
+                    return true;
+                }
+            };
 
     private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> {
         // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 1e10b6f..3554b54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -15,7 +15,6 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
 import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -26,7 +25,6 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -48,7 +46,6 @@
     private static final long AOD_ICONS_APPEAR_DURATION = 200;
 
     private final ContrastColorUtil mContrastColorUtil;
-    private final NotificationEntryManager mEntryManager;
     private final Runnable mUpdateStatusBarIcons = this::updateStatusBarIcons;
     private final StatusBarStateController mStatusBarStateController;
     private final NotificationMediaManager mMediaManager;
@@ -91,7 +88,6 @@
         mStatusBar = statusBar;
         mContrastColorUtil = ContrastColorUtil.getInstance(context);
         mContext = context;
-        mEntryManager = Dependency.get(NotificationEntryManager.class);
         mStatusBarStateController = statusBarStateController;
         mStatusBarStateController.addCallback(this);
         mMediaManager = notificationMediaManager;
@@ -247,7 +243,7 @@
         if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
             return false;
         }
-        if (mEntryManager.getNotificationData().isAmbient(entry.getKey()) && !showAmbient) {
+        if (entry.getRanking().isAmbient() && !showAmbient) {
             return false;
         }
         if (hideCurrentMedia && entry.getKey().equals(mMediaManager.getMediaNotificationKey())) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 6839fb4..8ebf574 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -3562,8 +3562,7 @@
 
     private void updateShowEmptyShadeView() {
         boolean showEmptyShadeView =
-                mBarState != StatusBarState.KEYGUARD &&
-                        mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+                mBarState != StatusBarState.KEYGUARD && !mEntryManager.hasActiveNotifications();
         showEmptyShadeView(showEmptyShadeView);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 01cd2b4..bfecaaa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -33,6 +33,7 @@
 import android.provider.Settings.Global;
 import android.service.notification.ZenModeConfig;
 import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
 import android.text.format.DateFormat;
 import android.util.Log;
 
@@ -127,7 +128,7 @@
 
     // Assume it's all good unless we hear otherwise.  We don't always seem
     // to get broadcasts that it *is* there.
-    IccCardConstants.State mSimState = IccCardConstants.State.READY;
+    int mSimState = TelephonyManager.SIM_STATE_READY;
 
     private boolean mZenVisible;
     private boolean mVolumeVisible;
@@ -307,25 +308,25 @@
     private final void updateSimState(Intent intent) {
         String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
         if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.ABSENT;
+            mSimState = TelephonyManager.SIM_STATE_READY;
         } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.CARD_IO_ERROR;
+            mSimState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
         } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.CARD_RESTRICTED;
+            mSimState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
         } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
-            mSimState = IccCardConstants.State.READY;
+            mSimState = TelephonyManager.SIM_STATE_READY;
         } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
             final String lockedReason =
                     intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON);
             if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PIN_REQUIRED;
+                mSimState = TelephonyManager.SIM_STATE_PIN_REQUIRED;
             } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) {
-                mSimState = IccCardConstants.State.PUK_REQUIRED;
+                mSimState = TelephonyManager.SIM_STATE_PUK_REQUIRED;
             } else {
-                mSimState = IccCardConstants.State.NETWORK_LOCKED;
+                mSimState = TelephonyManager.SIM_STATE_NETWORK_LOCKED;
             }
         } else {
-            mSimState = IccCardConstants.State.UNKNOWN;
+            mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
         }
     }
 
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/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 910300c..fafdf6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -148,7 +148,6 @@
 import com.android.systemui.charging.WirelessChargingAnimation;
 import com.android.systemui.classifier.FalsingLog;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
-import com.android.systemui.doze.DozeHost;
 import com.android.systemui.fragments.ExtensionFragmentListener;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
@@ -198,7 +197,6 @@
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationClicker;
@@ -210,6 +208,7 @@
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -222,7 +221,6 @@
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
 import com.android.systemui.statusbar.policy.ExtensionController;
-import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -342,7 +340,7 @@
     private PhoneStatusBarPolicy mIconPolicy;
     private StatusBarSignalPolicy mSignalPolicy;
 
-    private VolumeComponent mVolumeComponent;
+    private final VolumeComponent mVolumeComponent;
     private BrightnessMirrorController mBrightnessMirrorController;
     private boolean mBrightnessMirrorVisible;
     private BiometricUnlockController mBiometricUnlockController;
@@ -440,7 +438,7 @@
         ? new GestureRecorder("/sdcard/statusbar_gestures.dat")
         : null;
 
-    private ScreenPinningRequest mScreenPinningRequest;
+    private final ScreenPinningRequest mScreenPinningRequest;
 
     private final MetricsLogger mMetricsLogger;
 
@@ -658,7 +656,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AssistManager assistManager,
+            Lazy<AssistManager> assistManagerLazy,
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
@@ -670,8 +668,11 @@
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
+            ScreenPinningRequest screenPinningRequest,
             DozeScrimController dozeScrimController,
+            VolumeComponent volumeComponent,
             CommandQueue commandQueue,
+            Optional<Recents> recentsOptional,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -725,7 +726,7 @@
         mVisualStabilityManager = visualStabilityManager;
         mDeviceProvisionedController = deviceProvisionedController;
         mNavigationBarController = navigationBarController;
-        mAssistManager = assistManager;
+        mAssistManagerLazy = assistManagerLazy;
         mNotificationListener = notificationListener;
         mConfigurationController = configurationController;
         mStatusBarWindowController = statusBarWindowController;
@@ -736,9 +737,12 @@
         mScrimController = scrimController;
         mKeyguardLiftController = keyguardLiftController;
         mLockscreenWallpaperLazy = lockscreenWallpaperLazy;
+        mScreenPinningRequest = screenPinningRequest;
         mDozeScrimController = dozeScrimController;
         mBiometricUnlockControllerLazy = biometricUnlockControllerLazy;
+        mVolumeComponent = volumeComponent;
         mCommandQueue = commandQueue;
+        mRecentsOptional = recentsOptional;
         mPluginManager = pluginManager;
         mRemoteInputUriController = remoteInputUriController;
         mDividerOptional = dividerOptional;
@@ -789,7 +793,6 @@
                 R.bool.config_vibrateOnIconAnimation);
 
         DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
-        putComponent(StatusBar.class, this);
 
         // start old BaseStatusBar.start().
         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
@@ -803,8 +806,6 @@
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
 
-        mRecents = getComponent(Recents.class);
-
         mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
 
         // Connect in to the status bar manager service
@@ -893,9 +894,6 @@
         mDozeServiceHost.initialize(this, mNotificationIconAreaController,
                 mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager,
                 mNotificationPanel, mAmbientIndicationContainer);
-        putComponent(DozeHost.class, mDozeServiceHost);
-
-        mScreenPinningRequest = new ScreenPinningRequest(mContext);
 
         Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this);
 
@@ -1051,7 +1049,6 @@
         mGroupManager.setHeadsUpManager(mHeadsUpManager);
         mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
         mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
-        putComponent(HeadsUpManager.class, mHeadsUpManager);
 
         createNavigationBar(result);
 
@@ -1106,9 +1103,6 @@
         mMediaManager.setup(backdrop, backdrop.findViewById(R.id.backdrop_front),
                 backdrop.findViewById(R.id.backdrop_back), mScrimController, mLockscreenWallpaper);
 
-        // Other icons
-        mVolumeComponent = getComponent(VolumeComponent.class);
-
         mNotificationPanel.setUserSetupComplete(mUserSetup);
         if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             createUserSwitcher();
@@ -1229,7 +1223,8 @@
                         mContext,
                         mAllowNotificationLongPress,
                         mKeyguardBypassController,
-                        mStatusBarStateController);
+                        mStatusBarStateController,
+                        mNotificationLogger);
 
         mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanel,
                 mHeadsUpManager, mStatusBarWindow, mStackScroller, mDozeScrimController,
@@ -1251,8 +1246,8 @@
         final ActivityStarter activityStarter = Dependency.get(ActivityStarter.class);
 
         mNotificationActivityStarter = new StatusBarNotificationActivityStarter(mContext,
-                mCommandQueue, mAssistManager, mNotificationPanel, mPresenter, mEntryManager,
-                mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
+                mCommandQueue, mAssistManagerLazy.get(), mNotificationPanel, mPresenter,
+                mEntryManager, mHeadsUpManager, activityStarter, mActivityLaunchAnimator,
                 mBarService, mStatusBarStateController, mKeyguardManager, mDreamManager,
                 mRemoteInputManager, mStatusBarRemoteInputCallback, mGroupManager,
                 mLockscreenUserManager, this, mKeyguardStateController,
@@ -1433,7 +1428,7 @@
     }
 
     protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
-        if (mRecents == null) {
+        if (!mRecentsOptional.isPresent()) {
             return false;
         }
         int dockSide = WindowManagerProxy.getInstance().getDockSide();
@@ -1445,7 +1440,7 @@
             int createMode = navbarPos == NAV_BAR_POS_LEFT
                     ? SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT
                     : SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-            return mRecents.splitPrimaryTask(createMode, null, metricsDockAction);
+            return mRecentsOptional.get().splitPrimaryTask(createMode, null, metricsDockAction);
         } else {
             if (mDividerOptional.isPresent()) {
                 Divider divider = mDividerOptional.get();
@@ -2495,8 +2490,8 @@
         }
 
         if (DUMPTRUCK) {
-            synchronized (mEntryManager.getNotificationData()) {
-                mEntryManager.getNotificationData().dump(pw, "  ");
+            synchronized (mEntryManager) {
+                mEntryManager.dump(pw, "  ");
             }
 
             if (false) {
@@ -2600,7 +2595,7 @@
         final boolean afterKeyguardGone = mActivityIntentHelper.wouldLaunchResolverActivity(
                 intent, mLockscreenUserManager.getCurrentUserId());
         Runnable runnable = () -> {
-            mAssistManager.hideAssist();
+            mAssistManagerLazy.get().hideAssist();
             intent.setFlags(
                     Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             intent.addFlags(flags);
@@ -2754,11 +2749,7 @@
     };
 
     public void resetUserExpandedStates() {
-        ArrayList<NotificationEntry> activeNotifications = mEntryManager.getNotificationData()
-                .getActiveNotifications();
-        final int notificationCount = activeNotifications.size();
-        for (int i = 0; i < notificationCount; i++) {
-            NotificationEntry entry = activeNotifications.get(i);
+        for (NotificationEntry entry : mEntryManager.getVisibleNotifications()) {
             entry.resetUserExpansion();
         }
     }
@@ -2858,8 +2849,7 @@
         try {
             // consider the transition from peek to expanded to be a panel open,
             // but not one that clears notification effects.
-            int notificationLoad = mEntryManager.getNotificationData()
-                    .getActiveNotifications().size();
+            int notificationLoad = mEntryManager.getActiveNotificationsCount();
             mBarService.onPanelRevealed(false, notificationLoad);
         } catch (RemoteException ex) {
             // Won't fail unless the world has ended.
@@ -2877,8 +2867,7 @@
                     !mPresenter.isPresenterFullyCollapsed() &&
                             (mState == StatusBarState.SHADE
                                     || mState == StatusBarState.SHADE_LOCKED);
-            int notificationLoad = mEntryManager.getNotificationData().getActiveNotifications()
-                    .size();
+            int notificationLoad = mEntryManager.getActiveNotificationsCount();
             if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
                 notificationLoad = 1;
             }
@@ -3082,7 +3071,7 @@
         mStatusBarStateController.setLeaveOpenOnKeyguardHide(false);
         mPendingRemoteInputView = null;
         updateIsKeyguard();
-        mAssistManager.onLockscreenShown();
+        mAssistManagerLazy.get().onLockscreenShown();
     }
 
     public boolean hideKeyguard() {
@@ -3477,7 +3466,7 @@
             mCommandQueue.animateCollapsePanels(
                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
             visibilityChanged(false);
-            mAssistManager.hideAssist();
+            mAssistManagerLazy.get().hideAssist();
         }
         return false;
     }
@@ -3863,10 +3852,6 @@
         mScreenPinningRequest.showPrompt(taskId, allowCancel);
     }
 
-    public boolean hasActiveNotifications() {
-        return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
-    }
-
     @Override
     public void appTransitionCancelled(int displayId) {
         if (displayId == mDisplayId) {
@@ -4068,12 +4053,12 @@
     protected Display mDisplay;
     private int mDisplayId;
 
-    protected Recents mRecents;
+    private final Optional<Recents> mRecentsOptional;
 
     protected NotificationShelf mNotificationShelf;
     protected EmptyShadeView mEmptyShadeView;
 
-    private final AssistManager mAssistManager;
+    private final Lazy<AssistManager> mAssistManagerLazy;
 
     public boolean isDeviceInteractive() {
         return mDeviceInteractive;
@@ -4277,7 +4262,7 @@
                 // TODO: Dismiss Keyguard.
             }
             if (intent.isActivity()) {
-                mAssistManager.hideAssist();
+                mAssistManagerLazy.get().hideAssist();
             }
             if (intentSentUiThreadCallback != null) {
                 postOnUiThread(intentSentUiThreadCallback);
@@ -4395,9 +4380,7 @@
 
     @Override
     public void showAssistDisclosure() {
-        if (mAssistManager != null) {
-            mAssistManager.showDisclosure();
-        }
+        mAssistManagerLazy.get().showDisclosure();
     }
 
     public NotificationPanelView getPanel() {
@@ -4406,9 +4389,7 @@
 
     @Override
     public void startAssist(Bundle args) {
-        if (mAssistManager != null) {
-            mAssistManager.startAssist(args);
-        }
+        mAssistManagerLazy.get().startAssist(args);
     }
     // End Extra BaseStatusBarMethods.
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 9811f96..88f1c63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -37,6 +37,8 @@
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.FalsingManager;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -54,12 +56,12 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -70,6 +72,7 @@
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.volume.VolumeComponent;
 
 import java.util.Optional;
 
@@ -136,7 +139,7 @@
             VisualStabilityManager visualStabilityManager,
             DeviceProvisionedController deviceProvisionedController,
             NavigationBarController navigationBarController,
-            AssistManager assistManager,
+            Lazy<AssistManager> assistManagerLazy,
             NotificationListener notificationListener,
             ConfigurationController configurationController,
             StatusBarWindowController statusBarWindowController,
@@ -148,8 +151,11 @@
             Lazy<BiometricUnlockController> biometricUnlockControllerLazy,
             DozeServiceHost dozeServiceHost,
             PowerManager powerManager,
+            ScreenPinningRequest screenPinningRequest,
             DozeScrimController dozeScrimController,
+            VolumeComponent volumeComponent,
             CommandQueue commandQueue,
+            Optional<Recents> recentsOptional,
             PluginManager pluginManager,
             RemoteInputUriController remoteInputUriController,
             Optional<Divider> dividerOptional,
@@ -204,7 +210,7 @@
                 visualStabilityManager,
                 deviceProvisionedController,
                 navigationBarController,
-                assistManager,
+                assistManagerLazy,
                 notificationListener,
                 configurationController,
                 statusBarWindowController,
@@ -216,8 +222,11 @@
                 biometricUnlockControllerLazy,
                 dozeServiceHost,
                 powerManager,
+                screenPinningRequest,
                 dozeScrimController,
+                volumeComponent,
                 commandQueue,
+                recentsOptional,
                 pluginManager,
                 remoteInputUriController,
                 dividerOptional,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 64a45e1..b340813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -40,6 +40,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.view.RemoteAnimationAdapter;
+import android.view.View;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
@@ -75,7 +76,7 @@
  */
 public class StatusBarNotificationActivityStarter implements NotificationActivityStarter {
 
-    private static final String TAG = "NotificationClickHandler";
+    private static final String TAG = "NotifActivityStarter";
     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final AssistManager mAssistManager;
@@ -197,8 +198,6 @@
             return;
         }
 
-        final String notificationKey = sbn.getKey();
-
         boolean isActivityIntent = intent != null && intent.isActivity() && !isBubble;
         final boolean afterKeyguardGone = isActivityIntent
                 && mActivityIntentHelper.wouldLaunchResolverActivity(intent.getIntent(),
@@ -209,7 +208,7 @@
                 mLockscreenUserManager.getCurrentUserId());
         ActivityStarter.OnDismissAction postKeyguardAction =
                 () -> handleNotificationClickAfterKeyguardDismissed(
-                        sbn, row, controller, intent, notificationKey,
+                        sbn, row, controller, intent,
                         isActivityIntent, wasOccluded, showOverLockscreen);
         if (showOverLockscreen) {
             mIsCollapsingToShowActivityOverLockscreen = true;
@@ -225,12 +224,11 @@
             ExpandableNotificationRow row,
             RemoteInputController controller,
             PendingIntent intent,
-            String notificationKey,
             boolean isActivityIntent,
             boolean wasOccluded,
             boolean showOverLockscreen) {
         // TODO: Some of this code may be able to move to NotificationEntryManager.
-        if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(notificationKey)) {
+        if (mHeadsUpManager != null && mHeadsUpManager.isAlerting(sbn.getKey())) {
             // Release the HUN notification to the shade.
 
             if (mPresenter.isPresenterFullyCollapsed()) {
@@ -252,7 +250,7 @@
         }
         final StatusBarNotification parentToCancelFinal = parentToCancel;
         final Runnable runnable = () -> handleNotificationClickAfterPanelCollapsed(
-                sbn, row, controller, intent, notificationKey,
+                sbn, row, controller, intent,
                 isActivityIntent, wasOccluded, parentToCancelFinal);
 
         if (showOverLockscreen) {
@@ -273,10 +271,10 @@
             ExpandableNotificationRow row,
             RemoteInputController controller,
             PendingIntent intent,
-            String notificationKey,
             boolean isActivityIntent,
             boolean wasOccluded,
             StatusBarNotification parentToCancelFinal) {
+        String notificationKey = sbn.getKey();
         try {
             // The intent we are sending is for the application, which
             // won't have permission to immediately start an activity after
@@ -310,7 +308,7 @@
         if (!TextUtils.isEmpty(entry.remoteInputText)) {
             remoteInputText = entry.remoteInputText;
         }
-        if (!TextUtils.isEmpty(remoteInputText) && !controller.isSpinning(entry.getKey())) {
+        if (!TextUtils.isEmpty(remoteInputText) && !controller.isSpinning(notificationKey)) {
             fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT,
                     remoteInputText.toString());
         }
@@ -326,12 +324,10 @@
             collapseOnMainThread();
         }
 
-        final int count =
-                mEntryManager.getNotificationData().getActiveNotifications().size();
-        final int rank = mEntryManager.getNotificationData().getRank(notificationKey);
+        final int count = mEntryManager.getActiveNotificationsCount();
+        final int rank = entry.getRanking().getRank();
         NotificationVisibility.NotificationLocation location =
-                NotificationLogger.getNotificationLocation(
-                        mEntryManager.getNotificationData().get(notificationKey));
+                NotificationLogger.getNotificationLocation(entry);
         final NotificationVisibility nv = NotificationVisibility.obtain(notificationKey,
                 rank, count, true, location);
         try {
@@ -363,7 +359,7 @@
     }
 
     private void startNotificationIntent(PendingIntent intent, Intent fillInIntent,
-            ExpandableNotificationRow row, boolean wasOccluded, boolean isActivityIntent) {
+            View row, boolean wasOccluded, boolean isActivityIntent) {
         RemoteAnimationAdapter adapter = mActivityLaunchAnimator.getLaunchAnimation(row,
                 wasOccluded);
         try {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 38ff862..30e26e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -75,7 +75,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
-import java.util.ArrayList;
+import java.util.List;
 
 public class StatusBarNotificationPresenter implements NotificationPresenter,
         ConfigurationController.ConfigurationListener,
@@ -252,8 +252,8 @@
     }
 
     private void updateNotificationOnUiModeChanged() {
-        ArrayList<NotificationEntry> userNotifications
-                = mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+        List<NotificationEntry> userNotifications =
+                mEntryManager.getActiveNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
             NotificationEntry entry = userNotifications.get(i);
             ExpandableNotificationRow row = entry.getRow();
@@ -264,8 +264,8 @@
     }
 
     private void updateNotificationsOnDensityOrFontScaleChanged() {
-        ArrayList<NotificationEntry> userNotifications =
-                mEntryManager.getNotificationData().getNotificationsForCurrentUser();
+        List<NotificationEntry> userNotifications =
+                mEntryManager.getActiveNotificationsForCurrentUser();
         for (int i = 0; i < userNotifications.size(); i++) {
             NotificationEntry entry = userNotifications.get(i);
             entry.onDensityOrFontScaleChanged();
@@ -326,7 +326,7 @@
     }
 
     public boolean hasActiveNotifications() {
-        return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+        return mEntryManager.hasActiveNotifications();
     }
 
     public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
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/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index d488767..2e26711 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -23,6 +23,7 @@
 import android.content.res.TypedArray;
 import android.icu.text.DateFormat;
 import android.icu.text.DisplayContext;
+import android.os.Handler;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.widget.TextView;
@@ -47,6 +48,12 @@
     private 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;
+
             final String action = intent.getAction();
             if (Intent.ACTION_TIME_TICK.equals(action)
                     || Intent.ACTION_TIME_CHANGED.equals(action)
@@ -55,9 +62,9 @@
                 if (Intent.ACTION_LOCALE_CHANGED.equals(action)
                         || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
                     // need to get a fresh date format
-                    getHandler().post(() -> mDateFormat = null);
+                    handler.post(() -> mDateFormat = null);
                 }
-                getHandler().post(() -> updateClock());
+                handler.post(() -> updateClock());
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index 353d6a4..e675a7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -24,11 +24,11 @@
 import android.net.ConnectivityManager;
 import android.provider.Settings;
 import android.telephony.SubscriptionInfo;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
-import com.android.internal.telephony.IccCardConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -83,6 +83,18 @@
         getContext().unregisterReceiver(mReceiver);
     }
 
+    private boolean iccCardExist(int simState) {
+        return ((simState == TelephonyManager.SIM_STATE_PIN_REQUIRED)
+                || (simState == TelephonyManager.SIM_STATE_PUK_REQUIRED)
+                || (simState == TelephonyManager.SIM_STATE_NETWORK_LOCKED)
+                || (simState == TelephonyManager.SIM_STATE_READY)
+                || (simState == TelephonyManager.SIM_STATE_NOT_READY)
+                || (simState == TelephonyManager.SIM_STATE_PERM_DISABLED)
+                || (simState == TelephonyManager.SIM_STATE_CARD_IO_ERROR)
+                || (simState == TelephonyManager.SIM_STATE_CARD_RESTRICTED)
+                || (simState == TelephonyManager.SIM_STATE_LOADED));
+    }
+
     public void update() {
         boolean hasMobile = ConnectivityManager.from(mContext)
                 .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
@@ -102,9 +114,9 @@
         final int N = subs.size();
         for (int i = 0; i < N; i++) {
             int subId = subs.get(i).getSubscriptionId();
-            IccCardConstants.State simState = mKeyguardUpdateMonitor.getSimState(subId);
+            int simState = mKeyguardUpdateMonitor.getSimState(subId);
             CharSequence carrierName = subs.get(i).getCarrierName();
-            if (simState.iccCardExist() && !TextUtils.isEmpty(carrierName)) {
+            if (iccCardExist(simState) && !TextUtils.isEmpty(carrierName)) {
                 allSimsMissing = false;
                 displayText = carrierName;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index a3a9322..7587c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -22,6 +22,7 @@
 import android.net.wifi.WifiClient;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.UserManager;
 import android.util.Log;
 
@@ -110,7 +111,8 @@
             if (mWifiManager != null) {
                 if (mListening) {
                     if (mCallbacks.size() == 1) {
-                        mWifiManager.registerSoftApCallback(this, mMainHandler);
+                        mWifiManager.registerSoftApCallback(this,
+                                new HandlerExecutor(mMainHandler));
                     } else {
                         // mWifiManager#registerSoftApCallback triggers a call to
                         // onConnectedClientsChanged on the Main Handler. In order to always update
@@ -144,7 +146,7 @@
         if (mListening || !listening) return;
         mListening = true;
         if (mCallbacks.size() >= 1) {
-            mWifiManager.registerSoftApCallback(this, mMainHandler);
+            mWifiManager.registerSoftApCallback(this, new HandlerExecutor(mMainHandler));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index bae51b6..3f25bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -23,6 +23,8 @@
 import android.os.Looper;
 import android.os.Message;
 import android.provider.Settings.Global;
+import android.telephony.CellSignalStrength;
+import android.telephony.CellSignalStrengthCdma;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
@@ -50,6 +52,7 @@
 import java.util.BitSet;
 import java.util.concurrent.Executor;
 import java.util.Objects;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -477,6 +480,18 @@
     }
 
     /**
+     * Extracts the CellSignalStrengthCdma from SignalStrength then returns the level
+     */
+    private final int getCdmaLevel() {
+        List<CellSignalStrengthCdma> signalStrengthCdma =
+            mSignalStrength.getCellSignalStrengths(CellSignalStrengthCdma.class);
+        if (!signalStrengthCdma.isEmpty()) {
+            return signalStrengthCdma.get(0).getLevel();
+        }
+        return CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+    }
+
+    /**
      * Updates the current state based on mServiceState, mSignalStrength, mDataNetType,
      * mDataState, and mSimState.  It should be called any time one of these is updated.
      * This will call listeners if necessary.
@@ -491,7 +506,7 @@
                 && mSignalStrength != null;
         if (mCurrentState.connected) {
             if (!mSignalStrength.isGsm() && mConfig.alwaysShowCdmaRssi) {
-                mCurrentState.level = mSignalStrength.getCdmaLevel();
+                mCurrentState.level = getCdmaLevel();
             } else {
                 mCurrentState.level = mSignalStrength.getLevel();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 379cf1f..39de0f3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -50,8 +50,6 @@
 
     @Override
     public void start() {
-        putComponent(TvStatusBar.class, this);
-
         final IStatusBarService barService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
         mCommandQueue.addCallback(this);
diff --git a/packages/SystemUI/src/com/android/systemui/util/time/SystemClock.java b/packages/SystemUI/src/com/android/systemui/util/time/SystemClock.java
new file mode 100644
index 0000000..4316df1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/time/SystemClock.java
@@ -0,0 +1,46 @@
+/*
+ * 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.util.time;
+
+/**
+ * Testable wrapper around {@link android.os.SystemClock}.
+ *
+ * Dagger can inject this wrapper into your classes. The implementation just proxies calls to the
+ * real SystemClock.
+ *
+ * In tests, pass an instance of FakeSystemClock, which allows you to control the values returned by
+ * the various getters below.
+ */
+public interface SystemClock {
+    /** @see android.os.SystemClock#uptimeMillis() */
+    long uptimeMillis();
+
+    /** @see android.os.SystemClock#elapsedRealtime() */
+    long elapsedRealtime();
+
+    /** @see android.os.SystemClock#elapsedRealtimeNanos() */
+    long elapsedRealtimeNanos();
+
+    /** @see android.os.SystemClock#currentThreadTimeMillis() */
+    long currentThreadTimeMillis();
+
+    /** @see android.os.SystemClock#currentThreadTimeMicro() */
+    long currentThreadTimeMicro();
+
+    /** @see android.os.SystemClock#currentTimeMicro() */
+    long currentTimeMicro();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/time/SystemClockImpl.java b/packages/SystemUI/src/com/android/systemui/util/time/SystemClockImpl.java
new file mode 100644
index 0000000..532ea05
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/time/SystemClockImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.util.time;
+
+import javax.inject.Inject;
+
+/** Default implementation of {@link SystemClock}. */
+public class SystemClockImpl implements SystemClock {
+    @Inject
+    public SystemClockImpl() {}
+
+    @Override
+    public long uptimeMillis() {
+        return android.os.SystemClock.uptimeMillis();
+    }
+
+    @Override
+    public long elapsedRealtime() {
+        return android.os.SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public long elapsedRealtimeNanos() {
+        return android.os.SystemClock.elapsedRealtimeNanos();
+    }
+
+    @Override
+    public long currentThreadTimeMillis() {
+        return android.os.SystemClock.currentThreadTimeMillis();
+    }
+
+    @Override
+    public long currentThreadTimeMicro() {
+        return android.os.SystemClock.currentThreadTimeMicro();
+    }
+
+    @Override
+    public long currentTimeMicro() {
+        return android.os.SystemClock.currentTimeMicro();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index 25a5139..1c2a2fa 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -72,10 +72,11 @@
     );
 
     @Inject
-    public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator) {
+    public VolumeDialogComponent(Context context, KeyguardViewMediator keyguardViewMediator,
+            VolumeDialogControllerImpl volumeDialogController) {
         mContext = context;
         mKeyguardViewMediator = keyguardViewMediator;
-        mController = (VolumeDialogControllerImpl) Dependency.get(VolumeDialogController.class);
+        mController = volumeDialogController;
         mController.setUserActivityListener(this);
         // Allow plugins to reference the VolumeDialogController.
         Dependency.get(PluginDependencyProvider.class)
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 2c70fb4..02c699f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -52,13 +52,13 @@
 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;
 import com.android.settingslib.volume.MediaSessions;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
-import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.VolumeDialogController;
@@ -70,10 +70,13 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
+import dagger.Lazy;
+
 /**
  *  Source of truth for all state / events related to the volume dialog.  No presentation.
  *
@@ -115,7 +118,7 @@
     private final Context mContext;
     private AudioManager mAudio;
     private IAudioService mAudioService;
-    protected StatusBar mStatusBar;
+    private final Optional<Lazy<StatusBar>> mStatusBarOptionalLazy;
     private final NotificationManager mNoMan;
     private final SettingObserver mObserver;
     private final Receiver mReceiver = new Receiver();
@@ -141,8 +144,10 @@
     protected final BroadcastDispatcher mBroadcastDispatcher;
 
     @Inject
-    public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher) {
+    public VolumeDialogControllerImpl(Context context, BroadcastDispatcher broadcastDispatcher,
+            Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
         mContext = context.getApplicationContext();
+        mStatusBarOptionalLazy = statusBarOptionalLazy;
         mNotificationManager = (NotificationManager) mContext.getSystemService(
                 Context.NOTIFICATION_SERVICE);
         Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED);
@@ -161,7 +166,6 @@
         mHasVibrator = mVibrator != null && mVibrator.hasVibrator();
         mAudioService = IAudioService.Stub.asInterface(
                 ServiceManager.getService(Context.AUDIO_SERVICE));
-        updateStatusBar();
 
         boolean accessibilityVolumeStreamActive = context.getSystemService(
                 AccessibilityManager.class).isAccessibilityVolumeStreamActive();
@@ -444,23 +448,18 @@
         return changed;
     }
 
-    private void updateStatusBar() {
-        if (mStatusBar == null) {
-            mStatusBar = SysUiServiceProvider.getComponent(mContext, StatusBar.class);
-        }
-    }
-
     private boolean shouldShowUI(int flags) {
-        updateStatusBar();
         // if status bar isn't null, check if phone is in AOD, else check flags
         // since we could be using a different status bar
-        return mStatusBar != null ?
-                mStatusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
-                && mStatusBar.getWakefulnessState() !=
-                        WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
-                && mStatusBar.isDeviceInteractive()
-                && (flags & AudioManager.FLAG_SHOW_UI) != 0 && mShowVolumeDialog
-                : mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0;
+        return mStatusBarOptionalLazy.map(statusBarLazy -> {
+            StatusBar statusBar = statusBarLazy.get();
+            return statusBar.getWakefulnessState() != WakefulnessLifecycle.WAKEFULNESS_ASLEEP
+                    && statusBar.getWakefulnessState()
+                    != WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP
+                    && statusBar.isDeviceInteractive() && (flags & AudioManager.FLAG_SHOW_UI) != 0
+                    && mShowVolumeDialog;
+        }).orElse(
+                mShowVolumeDialog && (flags & AudioManager.FLAG_SHOW_UI) != 0);
     }
 
     boolean onVolumeChangedW(int stream, int flags) {
@@ -1084,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;
@@ -1103,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);
             }
         }
@@ -1117,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) {
@@ -1134,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;
                 }
@@ -1171,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/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
index b7431397..c0b8041 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java
@@ -56,31 +56,26 @@
         if (!mEnabled) return;
 
         mVolumeComponent.setEnableDialogs(enableVolumeUi, enableSafetyWarning);
-        putComponent(VolumeComponent.class, getVolumeComponent());
         setDefaultVolumeController();
     }
 
-    private VolumeComponent getVolumeComponent() {
-        return mVolumeComponent;
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         if (!mEnabled) return;
-        getVolumeComponent().onConfigurationChanged(newConfig);
+        mVolumeComponent.onConfigurationChanged(newConfig);
     }
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mEnabled="); pw.println(mEnabled);
         if (!mEnabled) return;
-        getVolumeComponent().dump(fd, pw, args);
+        mVolumeComponent.dump(fd, pw, args);
     }
 
     private void setDefaultVolumeController() {
         DndTile.setVisible(mContext, true);
         if (LOGD) Log.d(TAG, "Registering default volume controller");
-        getVolumeComponent().register();
+        mVolumeComponent.register();
     }
 }
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/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index d8eaaa1..1a1b679 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -54,7 +54,6 @@
 import android.testing.TestableLooper;
 import android.text.TextUtils;
 
-import com.android.internal.telephony.IccCardConstants;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
@@ -179,7 +178,7 @@
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
-        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         mCarrierTextController.updateCarrierText();
@@ -199,13 +198,13 @@
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
-        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(0)).thenReturn(TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getSimState(1)).thenReturn(
-                IccCardConstants.State.CARD_IO_ERROR);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         mCarrierTextController.mCallback.onSimStateChanged(3, 1,
-                IccCardConstants.State.CARD_IO_ERROR);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
                 ArgumentCaptor.forClass(
@@ -234,11 +233,11 @@
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(
                 new ArrayList<>());
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
-                IccCardConstants.State.CARD_IO_ERROR);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
         // This should not produce an out of bounds error, even though there are no subscriptions
         mCarrierTextController.mCallback.onSimStateChanged(0, -3,
-                IccCardConstants.State.CARD_IO_ERROR);
-        mCarrierTextController.mCallback.onSimStateChanged(0, 3, IccCardConstants.State.READY);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
+        mCarrierTextController.mCallback.onSimStateChanged(0, 3, TelephonyManager.SIM_STATE_READY);
         verify(mCarrierTextCallback, never()).updateCarrierInfo(any());
     }
 
@@ -254,10 +253,10 @@
                 new ArrayList<>());
 
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
-                IccCardConstants.State.CARD_IO_ERROR);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
         // This should not produce an out of bounds error, even though there are no subscriptions
         mCarrierTextController.mCallback.onSimStateChanged(0, 1,
-                IccCardConstants.State.CARD_IO_ERROR);
+                TelephonyManager.SIM_STATE_CARD_IO_ERROR);
 
         mTestableLooper.processAllMessages();
         verify(mCarrierTextCallback).updateCarrierInfo(
@@ -294,7 +293,8 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -318,7 +318,8 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION_ROAMING);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -342,7 +343,8 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION_NULL);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+            TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -366,7 +368,8 @@
         reset(mCarrierTextCallback);
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION_NULL);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+                TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
         mockWifi();
 
@@ -422,7 +425,8 @@
         List<SubscriptionInfo> list = new ArrayList<>();
         list.add(TEST_SUBSCRIPTION);
         list.add(TEST_SUBSCRIPTION);
-        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
+        when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
+            TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -446,8 +450,8 @@
         list.add(TEST_SUBSCRIPTION);
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
-                .thenReturn(IccCardConstants.State.READY)
-                .thenReturn(IccCardConstants.State.NOT_READY);
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -471,8 +475,8 @@
         list.add(TEST_SUBSCRIPTION);
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
-                .thenReturn(IccCardConstants.State.NOT_READY)
-                .thenReturn(IccCardConstants.State.READY);
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
 
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
@@ -497,9 +501,9 @@
         list.add(TEST_SUBSCRIPTION);
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt()))
-                .thenReturn(IccCardConstants.State.READY)
-                .thenReturn(IccCardConstants.State.NOT_READY)
-                .thenReturn(IccCardConstants.State.READY);
+                .thenReturn(TelephonyManager.SIM_STATE_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_NOT_READY)
+                .thenReturn(TelephonyManager.SIM_STATE_READY);
         when(mKeyguardUpdateMonitor.getFilteredSubscriptionInfo(anyBoolean())).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index c1da53b..7be3e2b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -546,8 +546,7 @@
         }
 
         @Override
-        protected void handleSimStateChange(int subId, int slotId,
-                IccCardConstants.State state) {
+        protected void handleSimStateChange(int subId, int slotId, int state) {
             mSimStateChanged.set(true);
             super.handleSimStateChange(subId, slotId, state);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
index bb4387eb..02a3766 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java
@@ -33,6 +33,7 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.widget.RemoteViews;
@@ -64,11 +65,12 @@
     private NotificationEntryListener mEntryListener;
     @Mock private NotificationEntryManager mEntryManager;
     @Mock private AppOpsController mAppOpsController;
+    @Mock private Handler mMainHandler;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController);
+        mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler);
         mListener = new ForegroundServiceNotificationListener(
                 mContext, mFsc, mEntryManager);
         ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
@@ -100,7 +102,7 @@
     public void testAppOps_appOpAddedToForegroundNotif() {
         // GIVEN a notification associated with a foreground service
         NotificationEntry entry = addFgEntry();
-        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+        when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry);
 
         // WHEN we are notified of a new app op for this notification
         mFsc.onAppOpChanged(
@@ -121,7 +123,7 @@
         // GIVEN a foreground service associated notification that already has the correct app op
         NotificationEntry entry = addFgEntry();
         entry.mActiveAppOps.add(AppOpsManager.OP_CAMERA);
-        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(entry);
+        when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(entry);
 
         // WHEN we are notified of the same app op for this notification
         mFsc.onAppOpChanged(
@@ -141,7 +143,7 @@
     public void testAppOps_appOpNotAddedToUnrelatedNotif() {
         // GIVEN no notification entries correspond to the newly updated appOp
         NotificationEntry entry = addFgEntry();
-        when(mEntryManager.getPendingOrCurrentNotif(entry.getKey())).thenReturn(null);
+        when(mEntryManager.getPendingOrActiveNotif(entry.getKey())).thenReturn(null);
 
         // WHEN a new app op is detected
         mFsc.onAppOpChanged(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 1e9000b..ba264c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -136,7 +136,6 @@
                 mTestableLooper.processAllMessages();
             }
         };
-        mScreenDecorations.mComponents = mContext.getComponents();
         reset(mTunerService);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index f792d7d..d847208 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -17,13 +17,9 @@
 import android.content.Context;
 import android.testing.LeakCheck;
 import android.testing.TestableContext;
-import android.util.ArrayMap;
 import android.view.Display;
 
-public class SysuiTestableContext extends TestableContext implements SysUiServiceProvider {
-
-    private ArrayMap<Class<?>, Object> mComponents;
-
+public class SysuiTestableContext extends TestableContext {
     public SysuiTestableContext(Context base) {
         super(base);
         setTheme(R.style.Theme_SystemUI);
@@ -34,21 +30,6 @@
         setTheme(R.style.Theme_SystemUI);
     }
 
-    public ArrayMap<Class<?>, Object> getComponents() {
-        if (mComponents == null) mComponents = new ArrayMap<>();
-        return mComponents;
-    }
-
-    @SuppressWarnings("unchecked")
-    public <T> T getComponent(Class<T> interfaceType) {
-        return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
-    }
-
-    public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
-        if (mComponents == null) mComponents = new ArrayMap<>();
-        mComponents.put(interfaceType, component);
-    }
-
     @Override
     public Context createDisplayContext(Display display) {
         if (display == null) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
index 540ac84..26185e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/appops/AppOpsControllerTest.java
@@ -39,6 +39,7 @@
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.DumpController;
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
@@ -66,6 +67,8 @@
     private AppOpsControllerImpl.H mMockHandler;
     @Mock
     private PermissionFlagsCache mFlagsCache;
+    @Mock
+    private DumpController mDumpController;
 
     private AppOpsControllerImpl mController;
     private TestableLooper mTestableLooper;
@@ -89,7 +92,8 @@
         when(mFlagsCache.getPermissionFlags(anyString(), anyString(),
                 eq(UserHandle.getUserHandleForUid(TEST_UID_NON_USER_SENSITIVE)))).thenReturn(0);
 
-        mController = new AppOpsControllerImpl(mContext, mTestableLooper.getLooper(), mFlagsCache);
+        mController = new AppOpsControllerImpl(mContext, mTestableLooper.getLooper(), mFlagsCache,
+                mDumpController);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
index fbb8e0c..f832b7b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/assist/AssistHandleBehaviorControllerTest.java
@@ -65,7 +65,7 @@
 
     @Mock private AssistUtils mMockAssistUtils;
     @Mock private Handler mMockHandler;
-    @Mock private PhenotypeHelper mMockPhenotypeHelper;
+    @Mock private DeviceConfigHelper mMockDeviceConfigHelper;
     @Mock private AssistHandleOffBehavior mMockOffBehavior;
     @Mock private AssistHandleLikeHomeBehavior mMockLikeHomeBehavior;
     @Mock private AssistHandleReminderExpBehavior mMockReminderExpBehavior;
@@ -97,7 +97,7 @@
                         mMockAssistUtils,
                         mMockHandler,
                         () -> mMockAssistHandleViewController,
-                        mMockPhenotypeHelper,
+                        mMockDeviceConfigHelper,
                         behaviorMap,
                         mMockNavigationModeController,
                         mMockDumpController);
@@ -216,7 +216,7 @@
     public void showAndGo_doesNothingIfRecentlyHidden() {
         // Arrange
         when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
-        when(mMockPhenotypeHelper.getLong(
+        when(mMockDeviceConfigHelper.getLong(
                 eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
                 anyLong())).thenReturn(10000L);
         mAssistHandleBehaviorController.showAndGo();
@@ -297,7 +297,7 @@
     public void showAndGoDelayed_doesNothingIfRecentlyHidden() {
         // Arrange
         when(mMockAssistUtils.getAssistComponentForUser(anyInt())).thenReturn(COMPONENT_NAME);
-        when(mMockPhenotypeHelper.getLong(
+        when(mMockDeviceConfigHelper.getLong(
                 eq(SystemUiDeviceConfigFlags.ASSIST_HANDLES_SHOWN_FREQUENCY_THRESHOLD_MS),
                 anyLong())).thenReturn(10000L);
         mAssistHandleBehaviorController.showAndGo();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 486fa12..f6375fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -53,7 +53,6 @@
 import com.android.internal.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.phone.StatusBar;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -88,8 +87,6 @@
 
         TestableContext context = spy(mContext);
 
-        mContext.putComponent(StatusBar.class, mock(StatusBar.class));
-
         when(context.getPackageManager()).thenReturn(mPackageManager);
         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE))
                 .thenReturn(true);
@@ -104,7 +101,6 @@
 
         mAuthController = new TestableAuthController(
                 context, mock(CommandQueue.class), new MockInjector());
-        mAuthController.mComponents = mContext.getComponents();
 
         mAuthController.start();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index b1a6bc6..8c9f759 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -72,12 +72,12 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -93,6 +93,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import dagger.Lazy;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
@@ -138,8 +140,6 @@
     private ExpandableNotificationRow mNonBubbleNotifRow;
 
     @Mock
-    private NotificationData mNotificationData;
-    @Mock
     private BubbleController.BubbleStateChangeListener mBubbleStateChangeListener;
     @Mock
     private BubbleController.BubbleExpandListener mBubbleExpandListener;
@@ -151,6 +151,8 @@
     ColorExtractor.GradientColors mGradientColors;
     @Mock
     private Resources mResources;
+    @Mock
+    private Lazy<ShadeController> mShadeController;
 
     private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     private BubbleData mBubbleData;
@@ -158,7 +160,6 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager);
         mContext.addMockSystemService(FaceManager.class, mFaceManager);
         when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
 
@@ -179,10 +180,9 @@
         mNonBubbleNotifRow = mNotificationTestHelper.createRow();
 
         // Return non-null notification data from the NEM
-        when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
-        when(mNotificationData.get(mRow.getEntry().getKey())).thenReturn(mRow.getEntry());
-        when(mNotificationData.getChannel(mRow.getEntry().getKey())).thenReturn(
-                mRow.getEntry().getChannel());
+        when(mNotificationEntryManager
+                .getActiveNotificationUnfiltered(mRow.getEntry().getKey())).thenReturn(
+                mRow.getEntry());
 
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
@@ -199,12 +199,15 @@
         mBubbleData = new BubbleData(mContext);
         mBubbleController = new TestableBubbleController(mContext,
                 mStatusBarWindowController,
+                mStatusBarStateController,
+                mShadeController,
                 mBubbleData,
                 mConfigurationController,
                 interruptionStateProvider,
                 mZenModeController,
                 mLockscreenUserManager,
-                mNotificationGroupManager);
+                mNotificationGroupManager,
+                mNotificationEntryManager);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
         mBubbleController.setExpandListener(mBubbleExpandListener);
 
@@ -686,15 +689,20 @@
     static class TestableBubbleController extends BubbleController {
         // Let's assume surfaces can be synchronized immediately.
         TestableBubbleController(Context context,
-                StatusBarWindowController statusBarWindowController, BubbleData data,
+                StatusBarWindowController statusBarWindowController,
+                StatusBarStateController statusBarStateController,
+                Lazy<ShadeController> shadeController,
+                BubbleData data,
                 ConfigurationController configurationController,
                 NotificationInterruptionStateProvider interruptionStateProvider,
                 ZenModeController zenModeController,
                 NotificationLockscreenUserManager lockscreenUserManager,
-                NotificationGroupManager groupManager) {
-            super(context, statusBarWindowController, data, Runnable::run,
-                    configurationController, interruptionStateProvider, zenModeController,
-                    lockscreenUserManager, groupManager);
+                NotificationGroupManager groupManager,
+                NotificationEntryManager entryManager) {
+            super(context,
+                    statusBarWindowController, statusBarStateController, shadeController,
+                    data, Runnable::run, configurationController, interruptionStateProvider,
+                    zenModeController, lockscreenUserManager, groupManager, entryManager);
         }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
index 67f65e6..a9be30b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.bubbles;
 
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Mockito.mock;
@@ -72,6 +74,8 @@
     private NotificationEntry mEntryB2;
     private NotificationEntry mEntryB3;
     private NotificationEntry mEntryC1;
+    private NotificationEntry mEntryInterruptive;
+    private NotificationEntry mEntryDismissed;
 
     private Bubble mBubbleA1;
     private Bubble mBubbleA2;
@@ -110,6 +114,13 @@
         mEntryB3 = createBubbleEntry(1, "b3", "package.b");
         mEntryC1 = createBubbleEntry(1, "c1", "package.c");
 
+        mEntryInterruptive = createBubbleEntry(1, "interruptive", "package.d");
+        modifyRanking(mEntryInterruptive)
+                .setVisuallyInterruptive(true)
+                .build();
+
+        mEntryDismissed = createBubbleEntry(1, "dismissed", "package.d");
+
         mBubbleA1 = new Bubble(mContext, mEntryA1);
         mBubbleA2 = new Bubble(mContext, mEntryA2);
         mBubbleA3 = new Bubble(mContext, mEntryA3);
@@ -160,6 +171,77 @@
         assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_USER_GESTURE);
     }
 
+    @Test
+    public void ifSuppress_hideFlyout() {
+        // Setup
+        mBubbleData.setListener(mListener);
+
+        // Test
+        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ true, /* showInShade */
+                true);
+
+        // Verify
+        verifyUpdateReceived();
+        BubbleData.Update update = mUpdateCaptor.getValue();
+        assertThat(update.addedBubble.showFlyoutForBubble()).isFalse();
+    }
+
+    @Test
+    public void ifInterruptiveAndNotSuppressed_thenShowFlyout() {
+        // Setup
+        mBubbleData.setListener(mListener);
+
+        // Test
+        mBubbleData.notificationEntryUpdated(mEntryInterruptive, /* suppressFlyout */
+                false, /* showInShade */
+                true);
+
+        // Verify
+        verifyUpdateReceived();
+        BubbleData.Update update = mUpdateCaptor.getValue();
+        assertThat(update.addedBubble.showFlyoutForBubble()).isTrue();
+    }
+
+    @Test
+    public void sameUpdate_InShade_thenHideFlyout() {
+        // Setup
+        mBubbleData.setListener(mListener);
+
+        // Test
+        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
+                true);
+        verifyUpdateReceived();
+
+        mBubbleData.notificationEntryUpdated(mEntryC1, /* suppressFlyout */ false, /* showInShade */
+                true);
+        verifyUpdateReceived();
+
+        // Verify
+        BubbleData.Update update = mUpdateCaptor.getValue();
+        assertThat(update.updatedBubble.showFlyoutForBubble()).isFalse();
+    }
+
+    @Test
+    public void sameUpdate_NotInShade_showFlyout() {
+        // Setup
+        mBubbleData.setListener(mListener);
+        setMetadataFlags(mEntryDismissed,
+                Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, /* enableFlag */ true);
+
+        // Test
+        mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */ false,
+                /* showInShade */ false);
+        verifyUpdateReceived();
+
+        mBubbleData.notificationEntryUpdated(mEntryDismissed, /* suppressFlyout */
+                false, /* showInShade */ false);
+        verifyUpdateReceived();
+
+        // Verify
+        BubbleData.Update update = mUpdateCaptor.getValue();
+        assertThat(update.updatedBubble.showFlyoutForBubble()).isTrue();
+    }
+
     // COLLAPSED / ADD
 
     /**
@@ -854,6 +936,23 @@
     }
 
     /**
+     * Sets the bubble metadata flags for this entry. These flags are normally set by
+     * NotificationManagerService when the notification is sent, however, these tests do not
+     * go through that path so we set them explicitly when testing.
+     */
+    private void setMetadataFlags(NotificationEntry entry, int flag, boolean enableFlag) {
+        Notification.BubbleMetadata bubbleMetadata =
+                entry.getSbn().getNotification().getBubbleMetadata();
+        int flags = bubbleMetadata.getFlags();
+        if (enableFlag) {
+            flags |= flag;
+        } else {
+            flags &= ~flag;
+        }
+        bubbleMetadata.setFlags(flags);
+    }
+
+    /**
      * No ExpandableNotificationRow is required to test BubbleData. This setup is all that is
      * required for BubbleData functionality and verification. NotificationTestHelper is used only
      * as a convenience to create a Notification w/BubbleMetadata.
@@ -888,7 +987,8 @@
 
     private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) {
         setPostTime(entry, postTime);
-        mBubbleData.notificationEntryUpdated(entry, /* suppressFlyout=*/ false);
+        mBubbleData.notificationEntryUpdated(entry, false /* suppressFlyout*/,
+                true /* showInShade */);
     }
 
     private void changeExpandedStateAtTime(boolean shouldBeExpanded, long time) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
index 839b5e4..466c1c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dock/DockManagerFake.java
@@ -37,6 +37,11 @@
         return false;
     }
 
+    @Override
+    public boolean isHidden() {
+        return false;
+    }
+
     public void setDockEvent(int event) {
         mCallback.onEvent(event);
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
index 98ec4594..c9bb401 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeDockHandlerTest.java
@@ -20,16 +20,11 @@
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.hardware.display.AmbientDisplayConfiguration;
-import android.os.Handler;
-import android.os.Looper;
 import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
 import androidx.test.filters.SmallTest;
@@ -49,10 +44,7 @@
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class DozeDockHandlerTest extends SysuiTestCase {
-    @Mock
-    private DozeMachine mMachine;
-    @Mock
-    private DozeHost mHost;
+    @Mock private DozeMachine mMachine;
     private AmbientDisplayConfiguration mConfig;
     private DockManagerFake mDockManagerFake;
     private DozeDockHandler mDockHandler;
@@ -61,146 +53,52 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mConfig = DozeConfigurationUtil.createMockConfig();
-        doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
-
         mDockManagerFake = spy(new DockManagerFake());
-        mDockHandler = new DozeDockHandler(mContext, mMachine, mHost, mConfig,
-                Handler.createAsync(Looper.myLooper()), mDockManagerFake);
+        mDockHandler = new DozeDockHandler(mConfig, mMachine, mDockManagerFake);
+
+        doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
+        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
     }
 
     @Test
-    public void testDockEventListener_registerAndUnregister() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-
+    public void transitionToInitialized_registersDockEventListener() {
         verify(mDockManagerFake).addListener(any());
+    }
 
-        mDockHandler.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
+    @Test
+    public void transitionToFinish_unregistersDockEventListener() {
+        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.FINISH);
 
         verify(mDockManagerFake).removeListener(any());
     }
 
     @Test
-    public void testOnEvent_dockedWhenDoze_requestPulse() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
+    public void onEvent_docked_requestsDockedAodState() {
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
 
-        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
+        verify(mMachine).requestState(eq(State.DOZE_AOD_DOCKED));
     }
 
     @Test
-    public void testOnEvent_dockedWhenDozeAoD_requestPulse() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
-
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
-
-        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
-    }
-
-    @Test
-    public void testOnEvent_dockedHideWhenPulsing_requestPulseOut() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
-
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
-
-        verify(mHost).stopPulsing();
-    }
-
-    @Test
-    public void testOnEvent_undockedWhenPulsing_requestPulseOut() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
-
-        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
-
-        verify(mHost).stopPulsing();
-    }
-
-    @Test
-    public void testOnEvent_undockedWhenDoze_neverRequestPulseOut() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
-        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
-
-        verify(mHost, never()).stopPulsing();
-    }
-
-    @Test
-    public void testOnEvent_undockedWhenDozeAndEnabledAoD_requestDozeAoD() {
-        doReturn(true).when(mConfig).alwaysOnEnabled(anyInt());
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
+    public void onEvent_noneWhileEnabledAod_requestsAodState() {
         mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
 
         verify(mMachine).requestState(eq(State.DOZE_AOD));
     }
 
     @Test
-    public void testTransitionToDoze_whenDocked_requestPulse() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-        mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE);
+    public void onEvent_noneWhileDisabledAod_requestsDozeState() {
+        doReturn(false).when(mConfig).alwaysOnEnabled(anyInt());
 
-        TestableLooper.get(this).processAllMessages();
-
-        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
-    }
-
-    @Test
-    public void testTransitionToDozeAoD_whenDocked_requestPulse() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
-        mDockHandler.transitionTo(State.INITIALIZED, DozeMachine.State.DOZE_AOD);
-
-        TestableLooper.get(this).processAllMessages();
-
-        verify(mMachine).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
-    }
-
-    @Test
-    public void testTransitionToDoze_whenDockedHide_neverRequestPulse() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
-        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
-
-        verify(mMachine, never()).requestPulse(eq(DozeEvent.PULSE_REASON_DOCKING));
-    }
-
-    @Test
-    public void testTransitionToDozeAoD_whenDockedHide_requestDoze() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.INITIALIZED);
-        mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_AOD);
-
-        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_AOD);
+        mDockManagerFake.setDockEvent(DockManager.STATE_NONE);
 
         verify(mMachine).requestState(eq(State.DOZE));
     }
 
     @Test
-    public void testTransitionToPulsing_whenDockedHide_requestPulseOut() {
-        mDockHandler.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE_PULSING);
-        when(mMachine.getPulseReason()).thenReturn(DozeEvent.PULSE_REASON_DOCKING);
+    public void onEvent_hide_requestsDozeState() {
         mDockManagerFake.setDockEvent(DockManager.STATE_DOCKED_HIDE);
 
-        mDockHandler.transitionTo(DozeMachine.State.INITIALIZED, State.DOZE_PULSING);
-
-        verify(mHost).stopPulsing();
+        verify(mMachine).requestState(eq(State.DOZE));
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index bbd2ab1..0723a4c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_REQUEST_PULSE;
@@ -45,6 +46,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dock.DockManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.wakelock.WakeLockFake;
@@ -66,6 +68,7 @@
     private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock
     private DozeLog mDozeLog;
+    @Mock private DockManager mDockManager;
     private DozeServiceFake mServiceFake;
     private WakeLockFake mWakeLockFake;
     private AmbientDisplayConfiguration mConfigMock;
@@ -78,9 +81,11 @@
         mWakeLockFake = new WakeLockFake();
         mConfigMock = mock(AmbientDisplayConfiguration.class);
         mPartMock = mock(DozeMachine.Part.class);
+        when(mDockManager.isDocked()).thenReturn(false);
+        when(mDockManager.isHidden()).thenReturn(false);
 
         mMachine = new DozeMachine(mServiceFake, mConfigMock, mWakeLockFake,
-                mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog);
+                mWakefulnessLifecycle, mock(BatteryController.class), mDozeLog, mDockManager);
         mMachine.setParts(new DozeMachine.Part[]{mPartMock});
     }
 
@@ -112,6 +117,28 @@
     }
 
     @Test
+    public void testInitialize_afterDocked_goesToDockedAod() {
+        when(mDockManager.isDocked()).thenReturn(true);
+
+        mMachine.requestState(INITIALIZED);
+
+        verify(mPartMock).transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+        assertEquals(DOZE_AOD_DOCKED, mMachine.getState());
+    }
+
+    @Test
+    public void testInitialize_afterDockPaused_goesToDoze() {
+        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+        when(mDockManager.isDocked()).thenReturn(true);
+        when(mDockManager.isHidden()).thenReturn(true);
+
+        mMachine.requestState(INITIALIZED);
+
+        verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+        assertEquals(DOZE, mMachine.getState());
+    }
+
+    @Test
     public void testPulseDone_goesToDoze() {
         when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
         mMachine.requestState(INITIALIZED);
@@ -138,6 +165,34 @@
     }
 
     @Test
+    public void testPulseDone_afterDocked_goesToDockedAoD() {
+        when(mDockManager.isDocked()).thenReturn(true);
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
+        mMachine.requestState(DOZE_PULSING);
+
+        mMachine.requestState(DOZE_PULSE_DONE);
+
+        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE_AOD_DOCKED);
+        assertEquals(DOZE_AOD_DOCKED, mMachine.getState());
+    }
+
+    @Test
+    public void testPulseDone_afterDockPaused_goesToDoze() {
+        when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+        when(mDockManager.isDocked()).thenReturn(true);
+        when(mDockManager.isHidden()).thenReturn(true);
+        mMachine.requestState(INITIALIZED);
+        mMachine.requestPulse(DozeEvent.PULSE_REASON_NOTIFICATION);
+        mMachine.requestState(DOZE_PULSING);
+
+        mMachine.requestState(DOZE_PULSE_DONE);
+
+        verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+        assertEquals(DOZE, mMachine.getState());
+    }
+
+    @Test
     public void testFinished_staysFinished() {
         mMachine.requestState(INITIALIZED);
         mMachine.requestState(FINISH);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 2ed0b4f..399f723f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
@@ -172,6 +173,16 @@
     }
 
     @Test
+    public void testDockedAod_usesLightSensor() {
+        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+        mScreen.transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+
+        mSensor.sendSensorEvent(3);
+
+        assertEquals(3, mServiceFake.screenBrightness);
+    }
+
+    @Test
     public void testDozingAfterPulsing_pausesLightSensor() throws Exception {
         mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
         mScreen.transitionTo(INITIALIZED, DOZE);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index b92f173..e8a3c0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.systemui.doze.DozeMachine.State.DOZE;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
+import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
 import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSING;
@@ -128,6 +129,14 @@
     }
 
     @Test
+    public void testScreen_onInDockedAod() {
+        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+        mScreen.transitionTo(INITIALIZED, DOZE_AOD_DOCKED);
+
+        assertEquals(Display.STATE_ON, mServiceFake.screenState);
+    }
+
+    @Test
     public void test_initialScreenStatePostedToHandler() {
         mHandlerFake.setMode(QUEUEING);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index 226bf6b..bf10609 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -69,10 +69,11 @@
     private AlarmManager mAlarmManager;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock
+    private DockManager mDockManager;
     private DozeTriggers mTriggers;
     private FakeSensorManager mSensors;
     private Sensor mTapSensor;
-    private DockManager mDockManagerFake;
     private FakeProximitySensor mProximitySensor;
 
     @Before
@@ -83,14 +84,13 @@
         mSensors = spy(new FakeSensorManager(mContext));
         mTapSensor = mSensors.getFakeTapSensor().getSensor();
         WakeLock wakeLock = new WakeLockFake();
-        mDockManagerFake = mock(DockManager.class);
         AsyncSensorManager asyncSensorManager =
                 new AsyncSensorManager(mSensors, null, new Handler());
         mProximitySensor = new FakeProximitySensor(getContext().getResources(), asyncSensorManager);
 
         mTriggers = new DozeTriggers(mContext, mMachine, mHost, mAlarmManager, config, parameters,
                 asyncSensorManager, Handler.createAsync(Looper.myLooper()), wakeLock, true,
-                mDockManagerFake, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
+                mDockManager, mProximitySensor, mock(DozeLog.class), mBroadcastDispatcher);
         waitForSensorManager();
     }
 
@@ -142,12 +142,24 @@
     }
 
     @Test
+    public void transitionToDockedAod_disablesTouchSensors() {
+        mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
+        waitForSensorManager();
+        verify(mSensors).requestTriggerSensor(any(), eq(mTapSensor));
+
+        mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.DOZE_AOD_DOCKED);
+        waitForSensorManager();
+
+        verify(mSensors).cancelTriggerSensor(any(), eq(mTapSensor));
+    }
+
+    @Test
     public void testDockEventListener_registerAndUnregister() {
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-        verify(mDockManagerFake).addListener(any());
+        verify(mDockManager).addListener(any());
 
         mTriggers.transitionTo(DozeMachine.State.DOZE, DozeMachine.State.FINISH);
-        verify(mDockManagerFake).removeListener(any());
+        verify(mDockManager).removeListener(any());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 47b35fd..e8f19238 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -687,7 +687,6 @@
 
     private void createPowerUi() {
         mPowerUI = new PowerUI(mContext, mBroadcastDispatcher, mStatusBarLazy);
-        mPowerUI.mComponents = mContext.getComponents();
         mPowerUI.mThermalService = mThermalServiceMock;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index a31fc3a..6cebb12 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -45,6 +45,7 @@
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.AutoTileManager;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -58,6 +59,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Optional;
+
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -100,7 +103,7 @@
                 mock(QSFactoryImpl.class), new Handler(), Looper.myLooper(),
                 mock(PluginManager.class), mock(TunerService.class),
                 () -> mock(AutoTileManager.class), mock(DumpController.class),
-                mock(BroadcastDispatcher.class));
+                mock(BroadcastDispatcher.class), Optional.of(mock(StatusBar.class)));
         qs.setHost(host);
 
         qs.setListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 0247c2f..fad7cbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.AutoTileManager;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService;
 
@@ -62,6 +63,7 @@
 import java.io.StringWriter;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
 
 import javax.inject.Provider;
 
@@ -88,6 +90,9 @@
     private BroadcastDispatcher mBroadcastDispatcher;
     @Mock
     private QSTile.State mMockState;
+    @Mock
+    private StatusBar mStatusBar;
+
     private Handler mHandler;
     private TestableLooper mLooper;
     private QSTileHost mQSTileHost;
@@ -99,7 +104,8 @@
         mHandler = new Handler(mLooper.getLooper());
         mQSTileHost = new TestQSTileHost(mContext, mIconController, mDefaultFactory, mHandler,
                 mLooper.getLooper(),
-                mPluginManager, mTunerService, mAutoTiles, mDumpController, mBroadcastDispatcher);
+                mPluginManager, mTunerService, mAutoTiles, mDumpController, mBroadcastDispatcher,
+                mStatusBar);
         setUpTileFactory();
         Settings.Secure.putStringForUser(mContext.getContentResolver(), QSTileHost.TILES_SETTING,
                 "", ActivityManager.getCurrentUser());
@@ -172,9 +178,10 @@
                 QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper,
                 PluginManager pluginManager, TunerService tunerService,
                 Provider<AutoTileManager> autoTiles, DumpController dumpController,
-                BroadcastDispatcher broadcastDispatcher) {
+                BroadcastDispatcher broadcastDispatcher, StatusBar statusBar) {
             super(context, iconController, defaultFactory, mainHandler, bgLooper, pluginManager,
-                    tunerService, autoTiles, dumpController, broadcastDispatcher);
+                    tunerService, autoTiles, dumpController, broadcastDispatcher,
+                    Optional.of(statusBar));
         }
 
         @Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index 824c50d..2737b19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -37,6 +37,7 @@
 import com.android.systemui.qs.tileimpl.QSFactoryImpl;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.statusbar.phone.AutoTileManager;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.tuner.TunerService;
@@ -51,6 +52,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Optional;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -74,6 +76,8 @@
     private AutoTileManager mAutoTileManager;
     @Mock
     private DumpController mDumpController;
+    @Mock
+    private StatusBar mStatusBar;
 
     @Before
     public void setUp() throws Exception {
@@ -89,7 +93,8 @@
                 mTunerService,
                 () -> mAutoTileManager,
                 mDumpController,
-                mBroadcastDispatcher);
+                mBroadcastDispatcher,
+                Optional.of(mStatusBar));
         mTileService = new TestTileServices(host, Looper.getMainLooper(), mBroadcastDispatcher);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java
index fcfdd11..d18b16b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryBuilder.java
@@ -20,6 +20,7 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager.Importance;
+import android.content.Context;
 import android.os.UserHandle;
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
@@ -92,6 +93,10 @@
         return this;
     }
 
+    public Notification.Builder modifyNotification(Context context) {
+        return mSbnBuilder.modifyNotification(context);
+    }
+
     public NotificationEntryBuilder setUser(UserHandle user) {
         mSbnBuilder.setUser(user);
         return this;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
index 86869bd..2f53a01 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationListenerTest.java
@@ -37,7 +37,6 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,7 +53,6 @@
 
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationListenerService.RankingMap mRanking;
-    @Mock private NotificationData mNotificationData;
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
@@ -74,8 +72,6 @@
                 new Handler(TestableLooper.get(this).getLooper()));
         mContext.addMockSystemService(NotificationManager.class, mNotificationManager);
 
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
         mListener = new NotificationListener(mContext);
         mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0,
                 new Notification(), UserHandle.CURRENT, null, 0);
@@ -90,7 +86,7 @@
 
     @Test
     public void testNotificationUpdateCallsUpdateNotification() {
-        when(mNotificationData.get(mSbn.getKey()))
+        when(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()))
                 .thenReturn(
                         new NotificationEntryBuilder()
                                 .setSbn(mSbn)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 548f7a8..d54e24ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.content.Intent.ACTION_USER_SWITCHED;
 import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
 
@@ -24,7 +25,6 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -49,7 +49,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -72,7 +71,6 @@
 
     // Dependency mocks:
     @Mock private NotificationEntryManager mEntryManager;
-    @Mock private NotificationData mNotificationData;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private StatusBarKeyguardViewManager mKeyguardViewManager;
     @Mock private BroadcastDispatcher mBroadcastDispatcher;
@@ -93,7 +91,6 @@
 
         when(mUserManager.getProfiles(mCurrentUserId)).thenReturn(Lists.newArrayList(
                 new UserInfo(mCurrentUserId, "", 0), new UserInfo(mCurrentUserId + 1, "", 0)));
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 Handler.createAsync(Looper.myLooper()));
 
@@ -170,9 +167,10 @@
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
         Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 1);
-        when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        NotificationEntry entry = new NotificationEntryBuilder().build();
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_LOW)
+                .build();
         entry.setBucket(BUCKET_SILENT);
 
         assertTrue(mLockscreenUserManager.shouldShowOnKeyguard(entry));
@@ -186,10 +184,12 @@
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
         Settings.Secure.putInt(mContext.getContentResolver(),
                 Settings.Secure.LOCK_SCREEN_SHOW_SILENT_NOTIFICATIONS, 0);
-        when(mNotificationData.isHighPriority(any())).thenReturn(false);
 
-        NotificationEntry entry = new NotificationEntryBuilder().build();
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setImportance(IMPORTANCE_LOW)
+                .build();
         entry.setBucket(BUCKET_SILENT);
+        entry.setIsHighPriority(true);
         assertFalse(mLockscreenUserManager.shouldShowOnKeyguard(entry));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 90bd0e9..88546b9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -26,7 +26,6 @@
 
 import android.annotation.Nullable;
 import android.app.ActivityManager;
-import android.app.Instrumentation;
 import android.app.Notification;
 import android.app.Notification.BubbleMetadata;
 import android.app.NotificationChannel;
@@ -40,8 +39,6 @@
 import android.view.LayoutInflater;
 import android.widget.RemoteViews;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.systemui.TestableDependency;
 import com.android.systemui.bubbles.BubbleController;
 import com.android.systemui.bubbles.BubblesTestActivity;
@@ -72,7 +69,6 @@
     private static final String GROUP_KEY = "gruKey";
 
     private final Context mContext;
-    private final Instrumentation mInstrumentation;
     private int mId;
     private final NotificationGroupManager mGroupManager;
     private ExpandableNotificationRow mRow;
@@ -83,7 +79,7 @@
         dependency.injectMockDependency(NotificationMediaManager.class);
         dependency.injectMockDependency(BubbleController.class);
         dependency.injectMockDependency(StatusBarWindowController.class);
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        dependency.injectMockDependency(SmartReplyController.class);
         StatusBarStateController stateController = mock(StatusBarStateController.class);
         mGroupManager = new NotificationGroupManager(stateController);
         mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 18649bf..99c94ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -46,7 +46,6 @@
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -73,7 +72,6 @@
 @TestableLooper.RunWithLooper
 public class NotificationViewHierarchyManagerTest extends SysuiTestCase {
     @Mock private NotificationPresenter mPresenter;
-    @Mock private NotificationData mNotificationData;
     @Spy private FakeListContainer mListContainer = new FakeListContainer();
 
     // Dependency mocks:
@@ -105,8 +103,6 @@
 
         mHelper = new NotificationTestHelper(mContext, mDependency);
 
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mHandler, mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
                 mock(StatusBarStateControllerImpl.class), mEntryManager,
@@ -139,7 +135,7 @@
         mListContainer.addContainerView(entry0.getRow());
         mListContainer.addContainerView(entry1.getRow());
         mListContainer.addContainerView(entry2.getRow());
-        when(mNotificationData.getActiveNotifications()).thenReturn(
+        when(mEntryManager.getVisibleNotifications()).thenReturn(
                 Lists.newArrayList(entry0, entry1, entry2));
 
         // Set up group manager to report that they should be bundled now.
@@ -168,7 +164,7 @@
 
         // Set up the prior state to look like one top level notification.
         mListContainer.addContainerView(entry0.getRow());
-        when(mNotificationData.getActiveNotifications()).thenReturn(
+        when(mEntryManager.getVisibleNotifications()).thenReturn(
                 Lists.newArrayList(entry0, entry1, entry2));
 
         // Set up group manager to report that they should not be bundled now.
@@ -197,7 +193,7 @@
 
         // Set up the prior state to look like a top level notification.
         mListContainer.addContainerView(entry0.getRow());
-        when(mNotificationData.getActiveNotifications()).thenReturn(
+        when(mEntryManager.getVisibleNotifications()).thenReturn(
                 Lists.newArrayList(entry0, entry1));
 
         // Set up group manager to report a suppressed summary now.
@@ -219,7 +215,7 @@
     public void testUpdateNotificationViews_appOps() throws Exception {
         NotificationEntry entry0 = createEntry();
         entry0.setRow(spy(entry0.getRow()));
-        when(mNotificationData.getActiveNotifications()).thenReturn(
+        when(mEntryManager.getVisibleNotifications()).thenReturn(
                 Lists.newArrayList(entry0));
         mListContainer.addContainerView(entry0.getRow());
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
index 820f465..d003b99 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/RankingBuilder.java
@@ -175,6 +175,11 @@
         return this;
     }
 
+    public RankingBuilder setVisuallyInterruptive(boolean interruptive) {
+        mIsVisuallyInterruptive = interruptive;
+        return this;
+    }
+
     public RankingBuilder setImportance(@Importance int importance) {
         mImportance = importance;
         return this;
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..94b3ac4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -16,7 +16,9 @@
 
 package com.android.systemui.statusbar;
 
+import android.annotation.Nullable;
 import android.app.Notification;
+import android.content.Context;
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 
@@ -32,7 +34,9 @@
     private String mTag;
     private int mUid;
     private int mInitialPid;
-    private Notification mNotification = new Notification();
+    @Nullable private Notification mNotification;
+    @Nullable private Notification.Builder mNotificationBuilder;
+    private Notification.BubbleMetadata mBubbleMetadata;
     private UserHandle mUser = UserHandle.of(0);
     private String mOverrideGroupKey;
     private long mPostTime;
@@ -54,6 +58,19 @@
     }
 
     public StatusBarNotification build() {
+        Notification notification;
+        if (mNotificationBuilder != null) {
+            notification = mNotificationBuilder.build();
+        } else if (mNotification != null) {
+            notification = mNotification;
+        } else {
+            notification = new Notification();
+        }
+
+        if (mBubbleMetadata != null) {
+            notification.setBubbleMetadata(mBubbleMetadata);
+        }
+
         return new StatusBarNotification(
                 mPkg,
                 mOpPkg,
@@ -61,7 +78,7 @@
                 mTag,
                 mUid,
                 mInitialPid,
-                mNotification,
+                notification,
                 mUser,
                 mOverrideGroupKey,
                 mPostTime);
@@ -102,6 +119,17 @@
         return this;
     }
 
+    public Notification.Builder modifyNotification(Context context) {
+        if (mNotification != null) {
+            mNotificationBuilder = new Notification.Builder(context, mNotification);
+            mNotification = null;
+        } else if (mNotificationBuilder == null) {
+            mNotificationBuilder = new Notification.Builder(context);
+        }
+
+        return mNotificationBuilder;
+    }
+
     public SbnBuilder setUser(UserHandle user) {
         mUser = user;
         return this;
@@ -116,4 +144,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/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index 86ef6e8..a98945f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 
 import static com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON;
@@ -28,7 +29,6 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doAnswer;
@@ -40,14 +40,15 @@
 
 import android.app.ActivityManager;
 import android.app.Notification;
-import android.app.NotificationManager;
+import android.app.NotificationChannel;
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -73,18 +74,18 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationRemoveInterceptor;
+import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinder;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
+import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.RowInflaterTask;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -93,6 +94,7 @@
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
+import com.android.systemui.util.Assert;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -104,13 +106,14 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper()
 public class NotificationEntryManagerTest extends SysuiTestCase {
     private static final String TEST_PACKAGE_NAME = "test";
     private static final int TEST_UID = 0;
@@ -123,7 +126,7 @@
     @Mock private NotificationRemoveInterceptor mRemoveInterceptor;
     @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
     @Mock private HeadsUpManager mHeadsUpManager;
-    @Mock private NotificationListenerService.RankingMap mRankingMap;
+    @Mock private RankingMap mRankingMap;
     @Mock private RemoteInputController mRemoteInputController;
 
     // Dependency mocks:
@@ -139,6 +142,7 @@
     @Mock private SmartReplyController mSmartReplyController;
     @Mock private RowInflaterTask mAsyncInflationTask;
     @Mock private NotificationRowBinder mMockedRowBinder;
+    @Mock private NotifLog mNotifLog;
 
     private int mId;
     private NotificationEntry mEntry;
@@ -146,43 +150,9 @@
     private TestableNotificationEntryManager mEntryManager;
     private CountDownLatch mCountDownLatch;
 
-    private class TestableNotificationEntryManager extends NotificationEntryManager {
-        private final CountDownLatch mCountDownLatch;
-
-        TestableNotificationEntryManager() {
-            super(
-                    new NotificationData(
-                            mock(NotificationSectionsFeatureManager.class),
-                            mock(NotifLog.class),
-                            mock(PeopleNotificationIdentifier.class)),
-                    mock(NotifLog.class));
-            mCountDownLatch = new CountDownLatch(1);
-        }
-
-        public void setNotificationData(NotificationData data) {
-            mNotificationData = data;
-        }
-
-        @Override
-        public void onAsyncInflationFinished(NotificationEntry entry,
-                @InflationFlag int inflatedFlags) {
-            super.onAsyncInflationFinished(entry, inflatedFlags);
-
-            mCountDownLatch.countDown();
-        }
-
-        public CountDownLatch getCountDownLatch() {
-            return mCountDownLatch;
-        }
-
-        public ArrayList<NotificationLifetimeExtender> getLifetimeExtenders() {
-            return mNotificationLifetimeExtenders;
-        }
-    }
-
     private void setUserSentiment(String key, int sentiment) {
         doAnswer(invocationOnMock -> {
-            NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+            Ranking ranking = (Ranking)
                     invocationOnMock.getArguments()[1];
             ranking.populate(
                     key,
@@ -190,16 +160,16 @@
                     false,
                     0,
                     0,
-                    NotificationManager.IMPORTANCE_DEFAULT,
+                    IMPORTANCE_DEFAULT,
                     null, null,
                     null, null, null, true, sentiment, false, -1, false, null, null, false, false);
             return true;
-        }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
+        }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
     }
 
     private void setSmartActions(String key, ArrayList<Notification.Action> smartActions) {
         doAnswer(invocationOnMock -> {
-            NotificationListenerService.Ranking ranking = (NotificationListenerService.Ranking)
+            Ranking ranking = (Ranking)
                     invocationOnMock.getArguments()[1];
             ranking.populate(
                     key,
@@ -207,13 +177,13 @@
                     false,
                     0,
                     0,
-                    NotificationManager.IMPORTANCE_DEFAULT,
+                    IMPORTANCE_DEFAULT,
                     null, null,
                     null, null, null, true,
-                    NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
+                    Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
                     false, smartActions, null, false, false);
             return true;
-        }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
+        }).when(mRankingMap).getRanking(eq(key), any(Ranking.class));
     }
 
     @Before
@@ -249,7 +219,18 @@
 
         mEntry.expandedIcon = mock(StatusBarIconView.class);
 
-        mEntryManager = new TestableNotificationEntryManager();
+        mEntryManager = new TestableNotificationEntryManager(
+                mNotifLog,
+                mGroupManager,
+                new NotificationRankingManager(
+                        () -> mock(NotificationMediaManager.class),
+                        mGroupManager,
+                        mHeadsUpManager,
+                        mock(NotificationFilter.class),
+                        mNotifLog,
+                        mock(NotificationSectionsFeatureManager.class)),
+                mEnvironment
+        );
         Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpWithPresenter(mPresenter, mListContainer, mHeadsUpManager);
         mEntryManager.addNotificationEntryListener(mEntryListener);
@@ -258,19 +239,19 @@
         NotificationRowBinderImpl notificationRowBinder =
                 new NotificationRowBinderImpl(mContext, true, /* allowLongPress */
                         mock(KeyguardBypassController.class),
-                        mock(StatusBarStateController.class));
+                        mock(StatusBarStateController.class),
+                        mock(NotificationLogger.class));
         notificationRowBinder.setUpWithPresenter(
                 mPresenter, mListContainer, mHeadsUpManager, mEntryManager, mBindCallback);
         notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
         mEntryManager.setRowBinder(notificationRowBinder);
 
         setUserSentiment(
-                mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
+                mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
     }
 
     @Test
     public void testAddNotification() throws Exception {
-        com.android.systemui.util.Assert.isNotMainThread();
         TestableLooper.get(this).processAllMessages();
 
         doAnswer(invocation -> {
@@ -299,21 +280,20 @@
         verify(mEntryListener).onNotificationAdded(entry);
         verify(mPresenter).updateNotificationViews();
 
-        assertEquals(mEntryManager.getNotificationData().get(mSbn.getKey()), entry);
+        assertEquals(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()), entry);
         assertNotNull(entry.getRow());
         assertEquals(mEntry.getUserSentiment(),
-                NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL);
+                Ranking.USER_SENTIMENT_NEUTRAL);
     }
 
     @Test
     public void testUpdateNotification() throws Exception {
-        com.android.systemui.util.Assert.isNotMainThread();
         TestableLooper.get(this).processAllMessages();
 
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         setUserSentiment(
-                mEntry.getKey(), NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+                mEntry.getKey(), Ranking.USER_SENTIMENT_NEGATIVE);
 
         mEntryManager.updateNotification(mSbn, mRankingMap);
         TestableLooper.get(this).processMessages(1);
@@ -327,19 +307,15 @@
         verify(mEntryListener).onPostEntryUpdated(mEntry);
 
         assertNotNull(mEntry.getRow());
-        assertEquals(mEntry.getUserSentiment(),
-                NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE);
+        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE,
+                mEntry.getUserSentiment());
     }
 
     @Test
     public void testUpdateNotification_prePostEntryOrder() throws Exception {
-        com.android.systemui.util.Assert.isNotMainThread();
         TestableLooper.get(this).processAllMessages();
 
-        NotificationData notifData = mock(NotificationData.class);
-        when(notifData.get(mEntry.getKey())).thenReturn(mEntry);
-
-        mEntryManager.setNotificationData(notifData);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         mEntryManager.updateNotification(mSbn, mRankingMap);
         TestableLooper.get(this).processMessages(1);
@@ -349,9 +325,8 @@
         verify(mEntryListener, never()).onInflationError(any(), any());
 
         // Ensure that update callbacks happen in correct order
-        InOrder order = inOrder(mEntryListener, notifData, mPresenter, mEntryListener);
+        InOrder order = inOrder(mEntryListener, mPresenter, mEntryListener);
         order.verify(mEntryListener).onPreEntryUpdated(mEntry);
-        order.verify(notifData).filterAndSort(anyString());
         order.verify(mPresenter).updateNotificationViews();
         order.verify(mEntryListener).onPostEntryUpdated(mEntry);
 
@@ -359,11 +334,12 @@
     }
 
     @Test
-    public void testRemoveNotification() throws Exception {
-        com.android.systemui.util.Assert.isNotMainThread();
+    public void testRemoveNotification() {
+        // Row inflation happens off thread, so pretend that this test looper is main
+        Assert.sMainLooper = TestableLooper.get(this).getLooper();
 
         mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         mEntryManager.removeNotification(mSbn.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
@@ -374,12 +350,11 @@
                 eq(mEntry), any(), eq(false) /* removedByUser */);
         verify(mRow).setRemoved();
 
-        assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
     }
 
     @Test
     public void testRemoveNotification_onEntryRemoveNotFiredIfEntryDoesntExist() {
-        com.android.systemui.util.Assert.isNotMainThread();
 
         mEntryManager.removeNotification("not_a_real_key", mRankingMap, UNDEFINED_DISMISS_REASON);
 
@@ -388,8 +363,7 @@
     }
 
     @Test
-    public void testRemoveNotification_whilePending() throws InterruptedException {
-        com.android.systemui.util.Assert.isNotMainThread();
+    public void testRemoveNotification_whilePending() {
 
         mEntryManager.setRowBinder(mMockedRowBinder);
 
@@ -408,7 +382,7 @@
 
         mEntry.setRow(mRow);
         mEntry.setInflationTask(mAsyncInflationTask);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
         setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
 
         mEntryManager.updateNotificationRanking(mRankingMap);
@@ -424,7 +398,7 @@
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.setRow(mRow);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
         setSmartActions(mEntry.getKey(), null);
 
         mEntryManager.updateNotificationRanking(mRankingMap);
@@ -438,7 +412,7 @@
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
 
         mEntry.setRow(null);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
         setSmartActions(mEntry.getKey(), new ArrayList<>(Arrays.asList(createAction())));
 
         mEntryManager.updateNotificationRanking(mRankingMap);
@@ -466,7 +440,7 @@
     public void testLifetimeExtenders_ifNotificationIsRetainedItIsntRemoved() {
         // GIVEN an entry manager with a notification
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN a lifetime extender that always tries to extend lifetime
         NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
@@ -479,15 +453,18 @@
         // THEN the extender is asked to manage the lifetime
         verify(extender).setShouldManageLifetime(mEntry, true);
         // THEN the notification is retained
-        assertNotNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+        assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener, never()).onEntryRemoved(eq(mEntry), any(), eq(false));
     }
 
     @Test
     public void testLifetimeExtenders_whenRetentionEndsNotificationIsRemoved() {
+        // Row inflation happens off thread, so pretend that this test looper is main
+        Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
         // GIVEN an entry manager with a notification whose life has been extended
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
         final FakeNotificationLifetimeExtender extender = new FakeNotificationLifetimeExtender();
         mEntryManager.addNotificationLifetimeExtender(extender);
         mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
@@ -498,7 +475,7 @@
         extender.getCallback().onSafeToRemove(mEntry.getKey());
 
         // THEN the notification is removed
-        assertNull(mEntryManager.getNotificationData().get(mSbn.getKey()));
+        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener).onEntryRemoved(eq(mEntry), any(), eq(false));
     }
 
@@ -506,7 +483,7 @@
     public void testLifetimeExtenders_whenNotificationUpdatedRetainersAreCanceled() {
         // GIVEN an entry manager with a notification whose life has been extended
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
         NotificationLifetimeExtender extender = mock(NotificationLifetimeExtender.class);
         when(extender.shouldExtendLifetime(mEntry)).thenReturn(true);
         mEntryManager.addNotificationLifetimeExtender(extender);
@@ -523,7 +500,7 @@
     public void testLifetimeExtenders_whenNewExtenderTakesPrecedenceOldExtenderIsCanceled() {
         // GIVEN an entry manager with a notification
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN two lifetime extenders, the first which never extends and the second which
         // always extends
@@ -554,15 +531,15 @@
      */
     @Test
     public void testPerformRemoveNotification_removedEntry() {
-        mEntryManager.getNotificationData().remove(mSbn.getKey(), null /* ranking */);
+        mEntryManager.removeNotification(mSbn.getKey(), null, 0);
         mEntryManager.performRemoveNotification(mSbn, REASON_CANCEL);
     }
 
     @Test
-    public void testRemoveInterceptor_interceptsDontGetRemoved() {
+    public void testRemoveInterceptor_interceptsDontGetRemoved() throws InterruptedException {
         // GIVEN an entry manager with a notification
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN interceptor that intercepts that entry
         when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
@@ -572,16 +549,19 @@
         mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
         // THEN the interceptor intercepts & the entry is not removed & no listeners are called
-        assertNotNull(mEntryManager.getNotificationData().get(mEntry.getKey()));
+        assertNotNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener, never()).onEntryRemoved(eq(mEntry),
                 any(NotificationVisibility.class), anyBoolean());
     }
 
     @Test
     public void testRemoveInterceptor_notInterceptedGetsRemoved() {
+        // Row inflation happens off thread, so pretend that this test looper is main
+        Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
         // GIVEN an entry manager with a notification
         mEntryManager.setRowBinder(mMockedRowBinder);
-        mEntryManager.getNotificationData().add(mEntry);
+        mEntryManager.addActiveNotificationForTest(mEntry);
 
         // GIVEN interceptor that doesn't intercept
         when(mRemoveInterceptor.onNotificationRemoveRequested(eq(mEntry.getKey()), anyInt()))
@@ -591,7 +571,7 @@
         mEntryManager.removeNotification(mEntry.getKey(), mRankingMap, UNDEFINED_DISMISS_REASON);
 
         // THEN the interceptor intercepts & the entry is not removed & no listeners are called
-        assertNull(mEntryManager.getNotificationData().get(mEntry.getKey()));
+        assertNull(mEntryManager.getActiveNotificationUnfiltered(mSbn.getKey()));
         verify(mEntryListener, atLeastOnce()).onEntryRemoved(eq(mEntry),
                 any(NotificationVisibility.class), anyBoolean());
     }
@@ -612,6 +592,63 @@
                 .build();
     }
 
+    /* Tests annexed from NotificationDataTest go here */
+
+    @Test
+    public void testChannelIsSetWhenAdded() {
+        NotificationChannel nc = new NotificationChannel(
+                "testId",
+                "testName",
+                IMPORTANCE_DEFAULT);
+
+        Ranking r = new RankingBuilder()
+                .setKey(mEntry.getKey())
+                .setChannel(nc)
+                .build();
+
+        RankingMap rm = new RankingMap(new Ranking[] { r });
+
+        // GIVEN: a notification is added, and the ranking updated
+        mEntryManager.addActiveNotificationForTest(mEntry);
+        mEntryManager.updateRanking(rm, "testReason");
+
+        // THEN the notification entry better have a channel on it
+        assertEquals(
+                "Channel must be set when adding a notification",
+                nc.getName(),
+                mEntry.getChannel().getName());
+    }
+
+    @Test
+    public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications() {
+        Assert.sMainLooper = TestableLooper.get(this).getLooper();
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        NotificationEntry e2 = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setId(mId++)
+                .setNotification(n.build())
+                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+                .build();
+
+        mEntryManager.addActiveNotificationForTest(mEntry);
+        mEntryManager.addActiveNotificationForTest(e2);
+
+        when(mEnvironment.isNotificationForCurrentProfiles(mEntry.getSbn())).thenReturn(false);
+        when(mEnvironment.isNotificationForCurrentProfiles(e2.getSbn())).thenReturn(true);
+
+        List<NotificationEntry> result = mEntryManager.getActiveNotificationsForCurrentUser();
+        assertEquals(result.size(), 1);
+        junit.framework.Assert.assertEquals(result.get(0), e2);
+    }
+
+    /* End annex */
+
     private Notification.Action createAction() {
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
index d85f275..68730d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationFilterTest.java
@@ -44,7 +44,7 @@
 import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -71,7 +71,7 @@
     @Mock
     ForegroundServiceController mFsc;
     @Mock
-    NotificationData.KeyguardEnvironment mEnvironment;
+    KeyguardEnvironment mEnvironment;
     private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
 
     private NotificationFilter mNotificationFilter;
@@ -96,7 +96,7 @@
                 new NotificationGroupManager(mock(StatusBarStateController.class)));
         mDependency.injectMockDependency(ShadeController.class);
         mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
-        mDependency.injectTestDependency(NotificationData.KeyguardEnvironment.class, mEnvironment);
+        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
         when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
         when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
         mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
index cc56949..133d52b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationListControllerTest.java
@@ -17,9 +17,7 @@
 package com.android.systemui.statusbar.notification;
 
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -34,14 +32,10 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
-import com.android.systemui.util.DeviceConfigProxyFake;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -67,13 +61,6 @@
     private NotificationEntryListener mEntryListener;
     private DeviceProvisionedListener mProvisionedListener;
 
-    // TODO: Remove this once EntryManager no longer needs to be mocked
-    private NotificationData mNotificationData =
-            new NotificationData(
-                    new NotificationSectionsFeatureManager(new DeviceConfigProxyFake(), mContext),
-                    mock(NotifLog.class),
-                    mock(PeopleNotificationIdentifier.class));
-
     private int mNextNotifId = 0;
 
     @Before
@@ -81,8 +68,6 @@
         MockitoAnnotations.initMocks(this);
         mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
 
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
         mController = new NotificationListController(
                 mEntryManager,
                 mListContainer,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
new file mode 100644
index 0000000..34beefe
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/TestableNotificationEntryManager.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification
+
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+
+import java.util.concurrent.CountDownLatch
+
+/**
+ * Enable some test capabilities for NEM without making everything public on the base class
+ */
+class TestableNotificationEntryManager(
+    log: NotifLog,
+    gm: NotificationGroupManager,
+    rm: NotificationRankingManager,
+    ke: KeyguardEnvironment
+) : NotificationEntryManager(log, gm, rm, ke) {
+
+    public var countDownLatch: CountDownLatch = CountDownLatch(1)
+
+    override fun onAsyncInflationFinished(entry: NotificationEntry?, inflatedFlags: Int) {
+        super.onAsyncInflationFinished(entry, inflatedFlags)
+        countDownLatch.countDown()
+    }
+
+    fun setUpForTest(
+        presenter: NotificationPresenter?,
+        listContainer: NotificationListContainer?,
+        headsUpManager: HeadsUpManagerPhone?
+    ) {
+        super.setUpWithPresenter(presenter, listContainer, headsUpManager)
+    }
+
+    fun setActiveNotificationList(activeList: List<NotificationEntry>) {
+        mSortedAndFiltered.clear()
+        mSortedAndFiltered.addAll(activeList)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
new file mode 100644
index 0000000..7326cd4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifListBuilderImplTest.java
@@ -0,0 +1,1199 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static com.android.systemui.statusbar.notification.collection.ListDumper.dumpList;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.NotifListBuilderImpl.OnRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeRenderListListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeSortListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeTransformGroupsListener;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.SectionsProvider;
+import com.android.systemui.util.Assert;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotifListBuilderImplTest extends SysuiTestCase {
+
+    private NotifListBuilderImpl mListBuilder;
+    private FakeSystemClock mSystemClock = new FakeSystemClock();
+
+    @Mock private NotifCollection mNotifCollection;
+    @Spy private OnBeforeTransformGroupsListener mOnBeforeTransformGroupsListener;
+    @Spy private OnBeforeSortListener mOnBeforeSortListener;
+    @Spy private OnBeforeRenderListListener mOnBeforeRenderListListener;
+    @Spy private OnRenderListListener mOnRenderListListener = list -> mBuiltList = list;
+
+    @Captor private ArgumentCaptor<CollectionReadyForBuildListener> mBuildListenerCaptor;
+
+    private CollectionReadyForBuildListener mReadyForBuildListener;
+    private List<NotificationEntryBuilder> mPendingSet = new ArrayList<>();
+    private List<NotificationEntry> mEntrySet = new ArrayList<>();
+    private List<ListEntry> mBuiltList;
+
+    private Map<String, Integer> mNextIdMap = new ArrayMap<>();
+    private int mNextRank = 0;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        Assert.sMainLooper = TestableLooper.get(this).getLooper();
+
+        mListBuilder = new NotifListBuilderImpl(mSystemClock);
+        mListBuilder.setOnRenderListListener(mOnRenderListListener);
+
+        mListBuilder.attach(mNotifCollection);
+
+        Mockito.verify(mNotifCollection).setBuildListener(mBuildListenerCaptor.capture());
+        mReadyForBuildListener = checkNotNull(mBuildListenerCaptor.getValue());
+    }
+
+    @Test
+    public void testNotifsAreSortedByRankAndWhen() {
+        // GIVEN a simple pipeline
+
+        // WHEN a series of notifs with jumbled ranks are added
+        addNotif(0, PACKAGE_1).setRank(2);
+        addNotif(1, PACKAGE_2).setRank(4).modifyNotification(mContext).setWhen(22);
+        addNotif(2, PACKAGE_3).setRank(4).modifyNotification(mContext).setWhen(33);
+        addNotif(3, PACKAGE_3).setRank(3);
+        addNotif(4, PACKAGE_5).setRank(4).modifyNotification(mContext).setWhen(11);
+        addNotif(5, PACKAGE_3).setRank(1);
+        addNotif(6, PACKAGE_1).setRank(0);
+        dispatchBuild();
+
+        // The final output is sorted based on rank
+        verifyBuiltList(
+                notif(6),
+                notif(5),
+                notif(0),
+                notif(3),
+                notif(2),
+                notif(1),
+                notif(4)
+        );
+    }
+
+    @Test
+    public void testNotifsAreGrouped() {
+        // GIVEN a simple pipeline
+
+        // WHEN a group is added
+        addGroupChild(0, PACKAGE_1, GROUP_1);
+        addGroupChild(1, PACKAGE_1, GROUP_1);
+        addGroupChild(2, PACKAGE_1, GROUP_1);
+        addGroupSummary(3, PACKAGE_1, GROUP_1);
+        dispatchBuild();
+
+        // THEN the notifs are grouped together
+        verifyBuiltList(
+                group(
+                        summary(3),
+                        child(0),
+                        child(1),
+                        child(2)
+                )
+        );
+    }
+
+    @Test
+    public void testNotifsWithDifferentGroupKeysAreGrouped() {
+        // GIVEN a simple pipeline
+
+        // WHEN a package posts two different groups
+        addGroupChild(0, PACKAGE_1, GROUP_1);
+        addGroupChild(1, PACKAGE_1, GROUP_2);
+        addGroupSummary(2, PACKAGE_1, GROUP_2);
+        addGroupChild(3, PACKAGE_1, GROUP_2);
+        addGroupChild(4, PACKAGE_1, GROUP_1);
+        addGroupChild(5, PACKAGE_1, GROUP_2);
+        addGroupChild(6, PACKAGE_1, GROUP_1);
+        addGroupSummary(7, PACKAGE_1, GROUP_1);
+        dispatchBuild();
+
+        // THEN the groups are separated separately
+        verifyBuiltList(
+                group(
+                        summary(2),
+                        child(1),
+                        child(3),
+                        child(5)
+                ),
+                group(
+                        summary(7),
+                        child(0),
+                        child(4),
+                        child(6)
+                )
+        );
+    }
+
+    @Test
+    public void testNotifsNotifChildrenAreSorted() {
+        // GIVEN a simple pipeline
+
+        // WHEN a group is added
+        addGroupChild(0, PACKAGE_1, GROUP_1).setRank(4);
+        addGroupChild(1, PACKAGE_1, GROUP_1).setRank(2)
+                .modifyNotification(mContext).setWhen(11);
+        addGroupChild(2, PACKAGE_1, GROUP_1).setRank(1);
+        addGroupChild(3, PACKAGE_1, GROUP_1).setRank(2)
+                .modifyNotification(mContext).setWhen(33);
+        addGroupChild(4, PACKAGE_1, GROUP_1).setRank(2)
+                .modifyNotification(mContext).setWhen(22);
+        addGroupChild(5, PACKAGE_1, GROUP_1).setRank(0);
+        addGroupSummary(6, PACKAGE_1, GROUP_1).setRank(3);
+        dispatchBuild();
+
+        // THEN the notifs are grouped together
+        verifyBuiltList(
+                group(
+                        summary(6),
+                        child(5),
+                        child(2),
+                        child(3),
+                        child(4),
+                        child(1),
+                        child(0)
+                )
+        );
+    }
+
+    @Test
+    public void testDuplicateGroupSummariesAreDiscarded() {
+        // GIVEN a simple pipeline
+
+        // WHEN a group with multiple summaries is added
+        addNotif(0, PACKAGE_3);
+        addGroupChild(1, PACKAGE_1, GROUP_1);
+        addGroupChild(2, PACKAGE_1, GROUP_1);
+        addGroupSummary(3, PACKAGE_1, GROUP_1).setPostTime(22);
+        addGroupSummary(4, PACKAGE_1, GROUP_1).setPostTime(33);
+        addNotif(5, PACKAGE_2);
+        addGroupSummary(6, PACKAGE_1, GROUP_1).setPostTime(11);
+        addGroupChild(7, PACKAGE_1, GROUP_1);
+        dispatchBuild();
+
+        // THEN only most recent summary is used
+        verifyBuiltList(
+                notif(0),
+                group(
+                        summary(4),
+                        child(1),
+                        child(2),
+                        child(7)
+                ),
+                notif(5)
+        );
+
+        // THEN the extra summaries have their parents set to null
+        assertNull(mEntrySet.get(3).getParent());
+        assertNull(mEntrySet.get(6).getParent());
+    }
+
+    @Test
+    public void testGroupsWithNoSummaryAreUngrouped() {
+        // GIVEN a group with no summary
+        addNotif(0, PACKAGE_2);
+        addGroupChild(1, PACKAGE_4, GROUP_2);
+        addGroupChild(2, PACKAGE_4, GROUP_2);
+        addGroupChild(3, PACKAGE_4, GROUP_2);
+        addGroupChild(4, PACKAGE_4, GROUP_2);
+
+        // WHEN we build the list
+        dispatchBuild();
+
+        // THEN the children aren't grouped
+        verifyBuiltList(
+                notif(0),
+                notif(1),
+                notif(2),
+                notif(3),
+                notif(4)
+        );
+    }
+
+    @Test
+    public void testGroupsWithNoChildrenAreUngrouped() {
+        // GIVEN a group with a summary but no children
+        addGroupSummary(0, PACKAGE_5, GROUP_1);
+        addNotif(1, PACKAGE_5);
+        addNotif(2, PACKAGE_1);
+
+        // WHEN we build the list
+        dispatchBuild();
+
+        // THEN the summary isn't grouped but is still added to the final list
+        verifyBuiltList(
+                notif(0),
+                notif(1),
+                notif(2)
+        );
+    }
+
+    @Test
+    public void testGroupsWithTooFewChildrenAreSplitUp() {
+        // GIVEN a group with one child
+        addGroupChild(0, PACKAGE_2, GROUP_1);
+        addGroupSummary(1, PACKAGE_2, GROUP_1);
+
+        // WHEN we build the list
+        dispatchBuild();
+
+        // THEN the child is added at top level and the summary is discarded
+        verifyBuiltList(
+                notif(0)
+        );
+
+        assertNull(mEntrySet.get(1).getParent());
+    }
+
+    @Test
+    public void testGroupsWhoLoseChildrenMidPipelineAreSplitUp() {
+        // GIVEN a group with two children
+        addGroupChild(0, PACKAGE_2, GROUP_1);
+        addGroupSummary(1, PACKAGE_2, GROUP_1);
+        addGroupChild(2, PACKAGE_2, GROUP_1);
+
+        // GIVEN a promoter that will promote one of children to top level
+        mListBuilder.addPromoter(new IdPromoter(0));
+
+        // WHEN we build the list
+        dispatchBuild();
+
+        // THEN both children end up at top level (because group is now too small)
+        verifyBuiltList(
+                notif(0),
+                notif(2)
+        );
+
+        // THEN the summary is discarded
+        assertNull(mEntrySet.get(1).getParent());
+    }
+
+    @Test
+    public void testPreviousParentsAreSetProperly() {
+        // GIVEN a notification that is initially added to the list
+        PackageFilter filter = new PackageFilter(PACKAGE_2);
+        filter.setEnabled(false);
+        mListBuilder.addFilter(filter);
+
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_3);
+        dispatchBuild();
+
+        // WHEN it is suddenly filtered out
+        filter.setEnabled(true);
+        dispatchBuild();
+
+        // THEN its previous parent indicates that it used to be added
+        assertNull(mEntrySet.get(1).getParent());
+        assertEquals(GroupEntry.ROOT_ENTRY, mEntrySet.get(1).getPreviousParent());
+    }
+
+    @Test
+    public void testThatAnnulledGroupsAndSummariesAreProperlyRolledBack() {
+        // GIVEN a registered transform groups listener
+        RecordingOnBeforeTransformGroupsListener listener =
+                new RecordingOnBeforeTransformGroupsListener();
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // GIVEN a malformed group that will be dismantled
+        addGroupChild(0, PACKAGE_2, GROUP_1);
+        addGroupSummary(1, PACKAGE_2, GROUP_1);
+        addNotif(2, PACKAGE_1);
+
+        // WHEN we build the list
+        dispatchBuild();
+
+        // THEN only the child appears in the final list
+        verifyBuiltList(
+                notif(0),
+                notif(2)
+        );
+
+        // THEN the list of newly visible entries doesn't contain the summary or the group
+        assertEquals(
+                Arrays.asList(
+                        mEntrySet.get(0),
+                        mEntrySet.get(2)),
+                listener.newlyVisibleEntries
+        );
+
+        // THEN the summary has a null parent and an unset firstAddedIteration
+        assertNull(mEntrySet.get(1).getParent());
+        assertEquals(-1, mEntrySet.get(1).mFirstAddedIteration);
+    }
+
+    @Test
+    public void testNotifsAreFiltered() {
+        // GIVEN a NotifFilter that filters out a specific package
+        NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
+        mListBuilder.addFilter(filter1);
+
+        // WHEN the pipeline is kicked off on a list of notifs
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_3);
+        addNotif(3, PACKAGE_2);
+        dispatchBuild();
+
+        // THEN the filter is called on each notif in the original set
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(0)), anyLong());
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(1)), anyLong());
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(2)), anyLong());
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(3)), anyLong());
+
+        // THEN the final list doesn't contain any filtered-out notifs
+        verifyBuiltList(
+                notif(0),
+                notif(2)
+        );
+
+        // THEN each filtered notif records the filter that did it
+        assertEquals(filter1, mEntrySet.get(1).mExcludingFilter);
+        assertEquals(filter1, mEntrySet.get(3).mExcludingFilter);
+    }
+
+    @Test
+    public void testNotifFiltersCanBePreempted() {
+        // GIVEN two notif filters
+        NotifFilter filter1 = spy(new PackageFilter(PACKAGE_2));
+        NotifFilter filter2 = spy(new PackageFilter(PACKAGE_5));
+        mListBuilder.addFilter(filter1);
+        mListBuilder.addFilter(filter2);
+
+        // WHEN the pipeline is kicked off on a list of notifs
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_5);
+        dispatchBuild();
+
+        // THEN both filters are called on the first notif but the second filter is never called
+        // on the already-filtered second notif
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(0)), anyLong());
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(1)), anyLong());
+        verify(filter1).shouldFilterOut(eq(mEntrySet.get(2)), anyLong());
+        verify(filter2).shouldFilterOut(eq(mEntrySet.get(0)), anyLong());
+        verify(filter2).shouldFilterOut(eq(mEntrySet.get(2)), anyLong());
+
+        // THEN the final list doesn't contain any filtered-out notifs
+        verifyBuiltList(
+                notif(0)
+        );
+
+        // THEN each filtered notif records the filter that did it
+        assertEquals(filter1, mEntrySet.get(1).mExcludingFilter);
+        assertEquals(filter2, mEntrySet.get(2).mExcludingFilter);
+    }
+
+    @Test
+    public void testNotifsArePromoted() {
+        // GIVEN a NotifPromoter that promotes certain notif IDs
+        NotifPromoter promoter = spy(new IdPromoter(1, 2));
+        mListBuilder.addPromoter(promoter);
+
+        // WHEN the pipeline is kicked off
+        addNotif(0, PACKAGE_1);
+        addGroupChild(1, PACKAGE_2, GROUP_1);
+        addGroupChild(2, PACKAGE_2, GROUP_1);
+        addGroupChild(3, PACKAGE_2, GROUP_1);
+        addGroupChild(4, PACKAGE_2, GROUP_1);
+        addGroupSummary(5, PACKAGE_2, GROUP_1);
+        addNotif(6, PACKAGE_3);
+        dispatchBuild();
+
+        // THEN the filter is called on each group child
+        verify(promoter).shouldPromoteToTopLevel(mEntrySet.get(1));
+        verify(promoter).shouldPromoteToTopLevel(mEntrySet.get(2));
+        verify(promoter).shouldPromoteToTopLevel(mEntrySet.get(3));
+        verify(promoter).shouldPromoteToTopLevel(mEntrySet.get(4));
+
+        // THEN the final list contains the promoted entries at top level
+        verifyBuiltList(
+                notif(0),
+                notif(2),
+                notif(3),
+                group(
+                        summary(5),
+                        child(1),
+                        child(4)),
+                notif(6)
+        );
+
+        // THEN each promoted notif records the promoter that did it
+        assertEquals(promoter, mEntrySet.get(2).mNotifPromoter);
+        assertEquals(promoter, mEntrySet.get(3).mNotifPromoter);
+    }
+
+    @Test
+    public void testNotifPromotersCanBePreempted() {
+        // GIVEN two notif promoters
+        NotifPromoter promoter1 = spy(new IdPromoter(1));
+        NotifPromoter promoter2 = spy(new IdPromoter(2));
+        mListBuilder.addPromoter(promoter1);
+        mListBuilder.addPromoter(promoter2);
+
+        // WHEN the pipeline is kicked off on some notifs and a group
+        addNotif(0, PACKAGE_1);
+        addGroupChild(1, PACKAGE_2, GROUP_1);
+        addGroupChild(2, PACKAGE_2, GROUP_1);
+        addGroupChild(3, PACKAGE_2, GROUP_1);
+        addGroupSummary(4, PACKAGE_2, GROUP_1);
+        addNotif(5, PACKAGE_3);
+        dispatchBuild();
+
+        for (NotificationEntry entry : mEntrySet) {
+            Log.d("pizza", "entry: " + entry.getKey() + " " + entry);
+        }
+
+        // THEN both promoters are called on each child, except for children that a previous
+        // promoter has already promoted
+        verify(promoter1).shouldPromoteToTopLevel(mEntrySet.get(1));
+        verify(promoter1).shouldPromoteToTopLevel(mEntrySet.get(2));
+        verify(promoter1).shouldPromoteToTopLevel(mEntrySet.get(3));
+
+        verify(promoter2).shouldPromoteToTopLevel(mEntrySet.get(1));
+        verify(promoter2).shouldPromoteToTopLevel(mEntrySet.get(3));
+
+        // THEN each promoter is recorded on each notif it promoted
+        assertEquals(promoter1, mEntrySet.get(2).mNotifPromoter);
+        assertEquals(promoter2, mEntrySet.get(3).mNotifPromoter);
+    }
+
+    @Test
+    public void testNotifsAreSectioned() {
+        // GIVEN a filter that removes all PACKAGE_4 notifs and a SectionsProvider that divides
+        // notifs based on package name
+        mListBuilder.addFilter(new PackageFilter(PACKAGE_4));
+        final SectionsProvider sectionsProvider = spy(new PackageSectioner());
+        mListBuilder.setSectionsProvider(sectionsProvider);
+
+        // WHEN we build a list with different packages
+        addNotif(0, PACKAGE_4);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_1);
+        addNotif(3, PACKAGE_3);
+        addGroupSummary(4, PACKAGE_2, GROUP_1);
+        addGroupChild(5, PACKAGE_2, GROUP_1);
+        addGroupChild(6, PACKAGE_2, GROUP_1);
+        addNotif(7, PACKAGE_1);
+        addNotif(8, PACKAGE_2);
+        addNotif(9, PACKAGE_5);
+        addNotif(10, PACKAGE_4);
+        dispatchBuild();
+
+        // THEN the list is sorted according to section
+        verifyBuiltList(
+                notif(2),
+                notif(7),
+                notif(1),
+                group(
+                        summary(4),
+                        child(5),
+                        child(6)
+                ),
+                notif(8),
+                notif(3),
+                notif(9)
+        );
+
+        // THEN the sections provider is called on all top level elements (but no children and no
+        // entries that were filtered out)
+        verify(sectionsProvider).getSection(mEntrySet.get(1));
+        verify(sectionsProvider).getSection(mEntrySet.get(2));
+        verify(sectionsProvider).getSection(mEntrySet.get(3));
+        verify(sectionsProvider).getSection(mEntrySet.get(7));
+        verify(sectionsProvider).getSection(mEntrySet.get(8));
+        verify(sectionsProvider).getSection(mEntrySet.get(9));
+        verify(sectionsProvider).getSection(mBuiltList.get(3));
+    }
+
+    @Test
+    public void testThatNotifComparatorsAreCalled() {
+        // GIVEN a set of comparators that care about specific packages
+        mListBuilder.setComparators(Arrays.asList(
+                new HypeComparator(PACKAGE_4),
+                new HypeComparator(PACKAGE_1, PACKAGE_3),
+                new HypeComparator(PACKAGE_2)
+        ));
+
+        // WHEN the pipeline is kicked off on a bunch of notifications
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_5);
+        addNotif(2, PACKAGE_3);
+        addNotif(3, PACKAGE_4);
+        addNotif(4, PACKAGE_2);
+        dispatchBuild();
+
+        // THEN the notifs are sorted according to the hierarchy of comparators
+        verifyBuiltList(
+                notif(3),
+                notif(0),
+                notif(2),
+                notif(4),
+                notif(1)
+        );
+    }
+
+    @Test
+    public void testListenersAndPluggablesAreFiredInOrder() {
+        // GIVEN a bunch of registered listeners and pluggables
+        NotifFilter filter = spy(new PackageFilter(PACKAGE_1));
+        NotifPromoter promoter = spy(new IdPromoter(3));
+        PackageSectioner sectioner = spy(new PackageSectioner());
+        NotifComparator comparator = spy(new HypeComparator(PACKAGE_4));
+        mListBuilder.addFilter(filter);
+        mListBuilder.addOnBeforeTransformGroupsListener(mOnBeforeTransformGroupsListener);
+        mListBuilder.addPromoter(promoter);
+        mListBuilder.addOnBeforeSortListener(mOnBeforeSortListener);
+        mListBuilder.setComparators(Collections.singletonList(comparator));
+        mListBuilder.setSectionsProvider(sectioner);
+        mListBuilder.addOnBeforeRenderListListener(mOnBeforeRenderListListener);
+
+        // WHEN a few new notifs are added
+        addNotif(0, PACKAGE_1);
+        addGroupSummary(1, PACKAGE_2, GROUP_1);
+        addGroupChild(2, PACKAGE_2, GROUP_1);
+        addGroupChild(3, PACKAGE_2, GROUP_1);
+        addNotif(4, PACKAGE_5);
+        addNotif(5, PACKAGE_5);
+        addNotif(6, PACKAGE_4);
+        dispatchBuild();
+
+        // THEN the pluggables and listeners are called in order
+        InOrder inOrder = inOrder(
+                filter,
+                mOnBeforeTransformGroupsListener,
+                promoter,
+                mOnBeforeSortListener,
+                sectioner,
+                comparator,
+                mOnBeforeRenderListListener,
+                mOnRenderListListener);
+
+        inOrder.verify(filter, atLeastOnce())
+                .shouldFilterOut(any(NotificationEntry.class), anyLong());
+        inOrder.verify(mOnBeforeTransformGroupsListener)
+                .onBeforeTransformGroups(anyList(), anyList());
+        inOrder.verify(promoter, atLeastOnce())
+                .shouldPromoteToTopLevel(any(NotificationEntry.class));
+        inOrder.verify(mOnBeforeSortListener).onBeforeSort(anyList());
+        inOrder.verify(sectioner, atLeastOnce()).getSection(any(ListEntry.class));
+        inOrder.verify(comparator, atLeastOnce())
+                .compare(any(ListEntry.class), any(ListEntry.class));
+        inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
+        inOrder.verify(mOnRenderListListener).onRenderList(anyList());
+    }
+
+    @Test
+    public void testThatPluggableInvalidationsTriggersRerun() {
+        // GIVEN a variety of pluggables
+        NotifFilter packageFilter = new PackageFilter(PACKAGE_1);
+        NotifPromoter idPromoter = new IdPromoter(4);
+        SectionsProvider sectionsProvider = new PackageSectioner();
+        NotifComparator hypeComparator = new HypeComparator(PACKAGE_2);
+
+        mListBuilder.addFilter(packageFilter);
+        mListBuilder.addPromoter(idPromoter);
+        mListBuilder.setSectionsProvider(sectionsProvider);
+        mListBuilder.setComparators(Collections.singletonList(hypeComparator));
+
+        // GIVEN a set of random notifs
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        addNotif(2, PACKAGE_3);
+        dispatchBuild();
+
+        // WHEN each pluggable is invalidated THEN the list is re-rendered
+
+        clearInvocations(mOnRenderListListener);
+        packageFilter.invalidateList();
+        verify(mOnRenderListListener).onRenderList(anyList());
+
+        clearInvocations(mOnRenderListListener);
+        idPromoter.invalidateList();
+        verify(mOnRenderListListener).onRenderList(anyList());
+
+        clearInvocations(mOnRenderListListener);
+        sectionsProvider.invalidateList();
+        verify(mOnRenderListListener).onRenderList(anyList());
+
+        clearInvocations(mOnRenderListListener);
+        hypeComparator.invalidateList();
+        verify(mOnRenderListListener).onRenderList(anyList());
+    }
+
+    @Test
+    public void testNotifFiltersAreAllSentTheSameNow() {
+        // GIVEN three notif filters
+        NotifFilter filter1 = spy(new PackageFilter(PACKAGE_5));
+        NotifFilter filter2 = spy(new PackageFilter(PACKAGE_5));
+        NotifFilter filter3 = spy(new PackageFilter(PACKAGE_5));
+        mListBuilder.addFilter(filter1);
+        mListBuilder.addFilter(filter2);
+        mListBuilder.addFilter(filter3);
+
+        // GIVEN the SystemClock is set to a particular time:
+        mSystemClock.setAutoIncrement(true);
+        mSystemClock.setUptimeMillis(47);
+
+        // WHEN the pipeline is kicked off on a list of notifs
+        addNotif(0, PACKAGE_1);
+        addNotif(1, PACKAGE_2);
+        dispatchBuild();
+
+        // THEN the value of `now` is the same for all calls to shouldFilterOut
+        verify(filter1).shouldFilterOut(mEntrySet.get(0), 47);
+        verify(filter2).shouldFilterOut(mEntrySet.get(0), 47);
+        verify(filter3).shouldFilterOut(mEntrySet.get(0), 47);
+        verify(filter1).shouldFilterOut(mEntrySet.get(1), 47);
+        verify(filter2).shouldFilterOut(mEntrySet.get(1), 47);
+        verify(filter3).shouldFilterOut(mEntrySet.get(1), 47);
+    }
+
+    @Test
+    public void testNewlyAddedEntries() {
+        // GIVEN a registered OnBeforeTransformGroupsListener
+        RecordingOnBeforeTransformGroupsListener listener =
+                spy(new RecordingOnBeforeTransformGroupsListener());
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // Given some new notifs
+        addNotif(0, PACKAGE_1);
+        addGroupChild(1, PACKAGE_2, GROUP_1);
+        addGroupSummary(2, PACKAGE_2, GROUP_1);
+        addGroupChild(3, PACKAGE_2, GROUP_1);
+        addNotif(4, PACKAGE_3);
+        addGroupChild(5, PACKAGE_2, GROUP_1);
+
+        // WHEN we run the pipeline
+        dispatchBuild();
+
+        verifyBuiltList(
+                notif(0),
+                group(
+                        summary(2),
+                        child(1),
+                        child(3),
+                        child(5)
+                ),
+                notif(4)
+        );
+
+        // THEN all the new notifs, including the new GroupEntry, are passed to the listener
+        verify(listener).onBeforeTransformGroups(
+                Arrays.asList(
+                        mEntrySet.get(0),
+                        mBuiltList.get(1),
+                        mEntrySet.get(4)
+                ),
+                Arrays.asList(
+                        mEntrySet.get(0),
+                        mEntrySet.get(1),
+                        mBuiltList.get(1),
+                        mEntrySet.get(2),
+                        mEntrySet.get(3),
+                        mEntrySet.get(4),
+                        mEntrySet.get(5)
+                )
+        );
+    }
+
+    @Test
+    public void testNewlyAddedEntriesOnSecondRun() {
+        // GIVEN a registered OnBeforeTransformGroupsListener
+        RecordingOnBeforeTransformGroupsListener listener =
+                spy(new RecordingOnBeforeTransformGroupsListener());
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // Given some notifs that have already been added (two of which are in malformed groups)
+        addNotif(0, PACKAGE_1);
+        addGroupChild(1, PACKAGE_2, GROUP_1);
+        addGroupChild(2, PACKAGE_3, GROUP_2);
+
+        dispatchBuild();
+        clearInvocations(listener);
+
+        // WHEN we run the pipeline
+        addGroupSummary(3, PACKAGE_2, GROUP_1);
+        addGroupChild(4, PACKAGE_3, GROUP_2);
+        addGroupSummary(5, PACKAGE_3, GROUP_2);
+        addGroupChild(6, PACKAGE_3, GROUP_2);
+        addNotif(7, PACKAGE_2);
+
+        dispatchBuild();
+
+        verifyBuiltList(
+                notif(0),
+                notif(1),
+                group(
+                        summary(5),
+                        child(2),
+                        child(4),
+                        child(6)
+                ),
+                notif(7)
+        );
+
+        // THEN all the new notifs, including the new GroupEntry, are passed to the listener
+        verify(listener).onBeforeTransformGroups(
+                Arrays.asList(
+                        mEntrySet.get(0),
+                        mEntrySet.get(1),
+                        mBuiltList.get(2),
+                        mEntrySet.get(7)
+                ),
+                Arrays.asList(
+                        mBuiltList.get(2),
+                        mEntrySet.get(4),
+                        mEntrySet.get(5),
+                        mEntrySet.get(6),
+                        mEntrySet.get(7)
+                )
+        );
+    }
+
+    @Test
+    public void testAnnulledGroupsHaveParentSetProperly() {
+        // GIVEN a list containing a small group that's already been built once
+        addGroupChild(0, PACKAGE_2, GROUP_2);
+        addGroupSummary(1, PACKAGE_2, GROUP_2);
+        addGroupChild(2, PACKAGE_2, GROUP_2);
+        dispatchBuild();
+
+        verifyBuiltList(
+                group(
+                        summary(1),
+                        child(0),
+                        child(2)
+                )
+        );
+        GroupEntry group = (GroupEntry) mBuiltList.get(0);
+
+        // WHEN a child is removed such that the group is no longer big enough
+        mEntrySet.remove(2);
+        dispatchBuild();
+
+        // THEN the group is annulled and its parent is set back to null
+        verifyBuiltList(
+                notif(0)
+        );
+        assertNull(group.getParent());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testOutOfOrderFilterInvalidationThrows() {
+        // GIVEN a NotifFilter that gets invalidated during the grouping stage
+        NotifFilter filter = new PackageFilter(PACKAGE_5);
+        OnBeforeTransformGroupsListener listener =
+                (list, newlyVisibleEntries) -> filter.invalidateList();
+        mListBuilder.addFilter(filter);
+        mListBuilder.addOnBeforeTransformGroupsListener(listener);
+
+        // WHEN we try to run the pipeline and the filter is invalidated
+        addNotif(0, PACKAGE_1);
+        dispatchBuild();
+
+        // Then an exception is thrown
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testOutOfOrderPrompterInvalidationThrows() {
+        // GIVEN a NotifFilter that gets invalidated during the grouping stage
+        NotifPromoter promoter = new IdPromoter(47);
+        OnBeforeSortListener listener =
+                (list) -> promoter.invalidateList();
+        mListBuilder.addPromoter(promoter);
+        mListBuilder.addOnBeforeSortListener(listener);
+
+        // WHEN we try to run the pipeline and the filter is invalidated
+        addNotif(0, PACKAGE_1);
+        dispatchBuild();
+
+        // Then an exception is thrown
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testOutOfOrderComparatorInvalidationThrows() {
+        // GIVEN a NotifFilter that gets invalidated during the grouping stage
+        NotifComparator comparator = new HypeComparator(PACKAGE_5);
+        OnBeforeRenderListListener listener =
+                (list) -> comparator.invalidateList();
+        mListBuilder.setComparators(Collections.singletonList(comparator));
+        mListBuilder.addOnBeforeRenderListListener(listener);
+
+        // WHEN we try to run the pipeline and the filter is invalidated
+        addNotif(0, PACKAGE_1);
+        dispatchBuild();
+
+        // Then an exception is thrown
+    }
+
+    /**
+     * Adds a notif to the collection that will be passed to the list builder when
+     * {@link #dispatchBuild()}s is called.
+     *
+     * @param index Index of this notification in the set. This must be the current size of the set.
+     *              it exists to improve readability of the resulting code, since later tests will
+     *              have to refer to notifs by index.
+     * @param packageId Package that the notif should be posted under
+     * @return A NotificationEntryBuilder that can be used to further modify the notif. Do not call
+     *         build() on the builder; that will be done on the next dispatchBuild().
+     */
+    private NotificationEntryBuilder addNotif(int index, String packageId) {
+        final NotificationEntryBuilder builder = new NotificationEntryBuilder()
+                .setPkg(packageId)
+                .setId(nextId(packageId))
+                .setRank(nextRank());
+
+        builder.modifyNotification(mContext)
+                .setContentTitle("Top level singleton")
+                .setChannelId("test_channel");
+
+        assertEquals(mEntrySet.size() + mPendingSet.size(), index);
+        mPendingSet.add(builder);
+        return builder;
+    }
+
+    /** Same behavior as {@link #addNotif(int, String)}. */
+    private NotificationEntryBuilder addGroupSummary(int index, String packageId, String groupId) {
+        final NotificationEntryBuilder builder = new NotificationEntryBuilder()
+                .setPkg(packageId)
+                .setId(nextId(packageId))
+                .setRank(nextRank());
+
+        builder.modifyNotification(mContext)
+                .setChannelId("test_channel")
+                .setContentTitle("Group summary")
+                .setGroup(groupId)
+                .setGroupSummary(true);
+
+        assertEquals(mEntrySet.size() + mPendingSet.size(), index);
+        mPendingSet.add(builder);
+        return builder;
+    }
+
+    /** Same behavior as {@link #addNotif(int, String)}. */
+    private NotificationEntryBuilder addGroupChild(int index, String packageId, String groupId) {
+        final NotificationEntryBuilder builder = new NotificationEntryBuilder()
+                .setPkg(packageId)
+                .setId(nextId(packageId))
+                .setRank(nextRank());
+
+        builder.modifyNotification(mContext)
+                .setChannelId("test_channel")
+                .setContentTitle("Group child")
+                .setGroup(groupId);
+
+        assertEquals(mEntrySet.size() + mPendingSet.size(), index);
+        mPendingSet.add(builder);
+        return builder;
+    }
+
+    private int nextId(String packageName) {
+        Integer nextId = mNextIdMap.get(packageName);
+        if (nextId == null) {
+            nextId = 0;
+        }
+        mNextIdMap.put(packageName, nextId + 1);
+        return nextId;
+    }
+
+    private int nextRank() {
+        int nextRank = mNextRank;
+        mNextRank++;
+        return nextRank;
+    }
+
+    private void dispatchBuild() {
+        if (mPendingSet.size() > 0) {
+            for (NotificationEntryBuilder builder : mPendingSet) {
+                mEntrySet.add(builder.build());
+            }
+            mPendingSet.clear();
+        }
+
+        mReadyForBuildListener.onBeginDispatchToListeners();
+        mReadyForBuildListener.onBuildList(mEntrySet);
+    }
+
+    private void verifyBuiltList(ExpectedEntry ...expectedEntries) {
+        try {
+            assertEquals(
+                    "List is the wrong length",
+                    expectedEntries.length,
+                    mBuiltList.size());
+
+            for (int i = 0; i < expectedEntries.length; i++) {
+                ListEntry outEntry = mBuiltList.get(i);
+                ExpectedEntry expectedEntry = expectedEntries[i];
+
+                if (expectedEntry instanceof ExpectedNotif) {
+                    assertEquals(
+                            "Entry " + i + " isn't a NotifEntry",
+                            NotificationEntry.class,
+                            outEntry.getClass());
+                    assertEquals(
+                            "Entry " + i + " doesn't match expected value.",
+                            ((ExpectedNotif) expectedEntry).entry, outEntry);
+                } else {
+                    ExpectedGroup cmpGroup = (ExpectedGroup) expectedEntry;
+
+                    assertEquals(
+                            "Entry " + i + " isn't a GroupEntry",
+                            GroupEntry.class,
+                            outEntry.getClass());
+
+                    GroupEntry outGroup = (GroupEntry) outEntry;
+
+                    assertEquals(
+                            "Summary notif for entry " + i
+                                    + " doesn't match expected value",
+                            cmpGroup.summary,
+                            outGroup.getSummary());
+                    assertEquals(
+                            "Summary notif for entry " + i
+                                        + " doesn't have proper parent",
+                            outGroup,
+                            outGroup.getSummary().getParent());
+
+                    assertEquals("Children for entry " + i,
+                            cmpGroup.children,
+                            outGroup.getChildren());
+
+                    for (int j = 0; j < outGroup.getChildren().size(); j++) {
+                        NotificationEntry child = outGroup.getChildren().get(j);
+                        assertEquals(
+                                "Child " + j + " for entry " + i
+                                        + " doesn't have proper parent",
+                                outGroup,
+                                child.getParent());
+                    }
+                }
+            }
+        } catch (AssertionError err) {
+            throw new AssertionError(
+                    "List under test failed verification:\n" + dumpList(mBuiltList), err);
+        }
+    }
+
+    private ExpectedNotif notif(int index) {
+        return new ExpectedNotif(mEntrySet.get(index));
+    }
+
+    private ExpectedGroup group(ExpectedSummary summary, ExpectedChild...children) {
+        return new ExpectedGroup(
+                summary.entry,
+                Arrays.stream(children)
+                        .map(child -> child.entry)
+                        .collect(Collectors.toList()));
+    }
+
+    private ExpectedSummary summary(int index) {
+        return new ExpectedSummary(mEntrySet.get(index));
+    }
+
+    private ExpectedChild child(int index) {
+        return new ExpectedChild(mEntrySet.get(index));
+    }
+
+    private abstract static class ExpectedEntry {
+    }
+
+    private static class ExpectedNotif extends ExpectedEntry {
+        public final NotificationEntry entry;
+
+        private ExpectedNotif(NotificationEntry entry) {
+            this.entry = entry;
+        }
+    }
+
+    private static class ExpectedGroup extends ExpectedEntry {
+        public final NotificationEntry summary;
+        public final List<NotificationEntry> children;
+
+        private ExpectedGroup(
+                NotificationEntry summary,
+                List<NotificationEntry> children) {
+            this.summary = summary;
+            this.children = children;
+        }
+    }
+
+    private static class ExpectedSummary {
+        public final NotificationEntry entry;
+
+        private ExpectedSummary(NotificationEntry entry) {
+            this.entry = entry;
+        }
+    }
+
+    private static class ExpectedChild {
+        public final NotificationEntry entry;
+
+        private ExpectedChild(NotificationEntry entry) {
+            this.entry = entry;
+        }
+    }
+
+    /** Filters out notifs from a particular package */
+    private static class PackageFilter extends NotifFilter {
+        private final String mPackageName;
+
+        private boolean mEnabled = true;
+
+        PackageFilter(String packageName) {
+            super("PackageFilter");
+
+            mPackageName = packageName;
+        }
+
+        @Override
+        public boolean shouldFilterOut(NotificationEntry entry, long now) {
+            return mEnabled && entry.getSbn().getPackageName().equals(mPackageName);
+        }
+
+        public void setEnabled(boolean enabled) {
+            mEnabled = enabled;
+        }
+    }
+
+    /** Promotes notifs with particular IDs */
+    private static class IdPromoter extends NotifPromoter {
+        private final List<Integer> mIds;
+
+        IdPromoter(Integer... ids) {
+            super("IdPromoter");
+            mIds = Arrays.asList(ids);
+        }
+
+        @Override
+        public boolean shouldPromoteToTopLevel(NotificationEntry child) {
+            return mIds.contains(child.getSbn().getId());
+        }
+    }
+
+    /** Sorts specific notifs above all others. */
+    private static class HypeComparator extends NotifComparator {
+
+        private final List<String> mPreferredPackages;
+
+        HypeComparator(String ...preferredPackages) {
+            super("HypeComparator");
+            mPreferredPackages = Arrays.asList(preferredPackages);
+        }
+
+        @Override
+        public int compare(ListEntry o1, ListEntry o2) {
+            boolean contains1 = mPreferredPackages.contains(
+                    o1.getRepresentativeEntry().getSbn().getPackageName());
+            boolean contains2 = mPreferredPackages.contains(
+                    o2.getRepresentativeEntry().getSbn().getPackageName());
+
+            return Boolean.compare(contains2, contains1);
+        }
+    }
+
+    /** Sorts notifs into sections based on their package name */
+    private static class PackageSectioner extends SectionsProvider {
+
+        PackageSectioner() {
+            super("PackageSectioner");
+        }
+
+        @Override
+        public int getSection(ListEntry entry) {
+            switch (entry.getRepresentativeEntry().getSbn().getPackageName()) {
+                case PACKAGE_1:
+                    return 1;
+                case PACKAGE_2:
+                    return 2;
+                case PACKAGE_3:
+                    return 3;
+                default:
+                    return 4;
+            }
+        }
+    }
+
+    private static class RecordingOnBeforeTransformGroupsListener
+            implements OnBeforeTransformGroupsListener {
+        public List<ListEntry> newlyVisibleEntries;
+
+        @Override
+        public void onBeforeTransformGroups(List<ListEntry> list,
+                List<ListEntry> newlyVisibleEntries) {
+            this.newlyVisibleEntries = newlyVisibleEntries;
+        }
+    }
+
+    private static final String PACKAGE_1 = "com.test1";
+    private static final String PACKAGE_2 = "com.test2";
+    private static final String PACKAGE_3 = "org.test3";
+    private static final String PACKAGE_4 = "com.test4";
+    private static final String PACKAGE_5 = "com.test5";
+
+    private static final String GROUP_1 = "group_1";
+    private static final String GROUP_2 = "group_2";
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
deleted file mode 100644
index 1a469d8..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ /dev/null
@@ -1,697 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.systemui.statusbar.notification.collection;
-
-import static android.app.Notification.CATEGORY_ALARM;
-import static android.app.Notification.CATEGORY_CALL;
-import static android.app.Notification.CATEGORY_EVENT;
-import static android.app.Notification.CATEGORY_MESSAGE;
-import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
-
-import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_RANK;
-import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
-import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT;
-
-import static junit.framework.Assert.assertEquals;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.Manifest;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Person;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.service.notification.NotificationListenerService;
-import android.service.notification.NotificationListenerService.Ranking;
-import android.service.notification.SnoozeCriterion;
-import android.service.notification.StatusBarNotification;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.Dependency;
-import com.android.systemui.ForegroundServiceController;
-import com.android.systemui.InitController;
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationEntryBuilder;
-import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationTestHelper;
-import com.android.systemui.statusbar.RankingBuilder;
-import com.android.systemui.statusbar.SbnBuilder;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData.KeyguardEnvironment;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.ShadeController;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-public class NotificationDataTest extends SysuiTestCase {
-
-    private static final int UID_NORMAL = 123;
-    private static final int UID_ALLOW_DURING_SETUP = 456;
-    private static final NotificationChannel NOTIFICATION_CHANNEL =
-            new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
-
-    private NotificationEntry mEntry;
-
-    @Mock
-    ForegroundServiceController mFsc;
-    @Mock
-    NotificationData.KeyguardEnvironment mEnvironment;
-
-    private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
-    private TestableNotificationData mNotificationData;
-    private ExpandableNotificationRow mRow;
-
-    @Before
-    public void setUp() throws Exception {
-        com.android.systemui.util.Assert.sMainLooper = TestableLooper.get(this).getLooper();
-        MockitoAnnotations.initMocks(this);
-
-        mEntry = new NotificationEntryBuilder()
-                .setUid(UID_NORMAL)
-                .build();
-
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_NORMAL)))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-        when(mMockPackageManager.checkUidPermission(
-                eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
-                eq(UID_ALLOW_DURING_SETUP)))
-                .thenReturn(PackageManager.PERMISSION_GRANTED);
-
-        mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
-        mDependency.injectTestDependency(NotificationGroupManager.class,
-                new NotificationGroupManager(mock(StatusBarStateController.class)));
-        mDependency.injectMockDependency(ShadeController.class);
-        mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
-        mDependency.injectTestDependency(KeyguardEnvironment.class, mEnvironment);
-        when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
-        when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
-        mNotificationData = new TestableNotificationData(
-                mock(NotificationSectionsFeatureManager.class));
-        mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class), "");
-        mRow = new NotificationTestHelper(getContext(), mDependency).createRow();
-        Dependency.get(InitController.class).executePostInitTasks();
-    }
-
-    @Test
-    public void testChannelSetWhenAdded() {
-        Bundle override = new Bundle();
-        override.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
-        mNotificationData.rankingOverrides.put(mRow.getEntry().getKey(), override);
-        mNotificationData.add(mRow.getEntry());
-        assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().getChannel());
-    }
-
-    @Test
-    public void testGetNotificationsForCurrentUser_shouldFilterNonCurrentUserNotifications()
-            throws Exception {
-        mNotificationData.add(mRow.getEntry());
-        ExpandableNotificationRow row2 = new NotificationTestHelper(getContext(), mDependency)
-                .createRow();
-        mNotificationData.add(row2.getEntry());
-
-        when(mEnvironment.isNotificationForCurrentProfiles(
-                mRow.getEntry().getSbn())).thenReturn(false);
-        when(mEnvironment.isNotificationForCurrentProfiles(
-                row2.getEntry().getSbn())).thenReturn(true);
-        ArrayList<NotificationEntry> result =
-                mNotificationData.getNotificationsForCurrentUser();
-
-        assertEquals(result.size(), 1);
-        junit.framework.Assert.assertEquals(result.get(0), row2.getEntry());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_foreground() {
-        initStatusBarNotification(false);
-
-        mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
-        mEntry.setRow(mRow);
-        mNotificationData.add(mEntry);
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_VIS_EFFECTS, 255);
-        mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
-        assertTrue(mEntry.isExemptFromDndVisualSuppression());
-        assertFalse(mEntry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_media() {
-        initStatusBarNotification(false);
-        Notification n = mEntry.getSbn().getNotification();
-        Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
-        nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
-        n = nb.build();
-        modifySbn(mEntry)
-                .setNotification(n)
-                .build();
-        mEntry.setRow(mRow);
-        mNotificationData.add(mEntry);
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_VIS_EFFECTS, 255);
-        mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
-        assertTrue(mEntry.isExemptFromDndVisualSuppression());
-        assertFalse(mEntry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsExemptFromDndVisualSuppression_system() {
-        initStatusBarNotification(false);
-        mEntry.setRow(mRow);
-        mEntry.mIsSystemNotification = true;
-        mNotificationData.add(mEntry);
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_VIS_EFFECTS, 255);
-        mNotificationData.rankingOverrides.put(mEntry.getKey(), override);
-
-        assertTrue(mEntry.isExemptFromDndVisualSuppression());
-        assertFalse(mEntry.shouldSuppressAmbient());
-    }
-
-    @Test
-    public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
-        initStatusBarNotification(false);
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setUid(UID_NORMAL)
-                .build();
-        entry.setRow(mRow);
-        entry.mIsSystemNotification = true;
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_VIS_EFFECTS, NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
-        mNotificationData.rankingOverrides.put(entry.getKey(), override);
-        mNotificationData.add(entry);
-
-        modifySbn(entry)
-                .setNotification(
-                        new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build())
-                .build();
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-        assertTrue(entry.shouldSuppressAmbient());
-
-        modifySbn(entry)
-                .setNotification(
-                        new Notification.Builder(mContext, "")
-                                .setCategory(CATEGORY_REMINDER)
-                                .build())
-                .build();
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        modifySbn(entry)
-                .setNotification(
-                        new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build())
-                .build();
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        modifySbn(entry)
-                .setNotification(
-                        new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build())
-                .build();
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-
-        modifySbn(entry)
-                .setNotification(
-                        new Notification.Builder(mContext, "")
-                                .setCategory(CATEGORY_MESSAGE)
-                                .build())
-                .build();
-        assertFalse(entry.isExemptFromDndVisualSuppression());
-    }
-
-    @Test
-    public void testCreateNotificationDataEntry_RankingUpdate() {
-        StatusBarNotification sbn = new SbnBuilder().build();
-        sbn.getNotification().actions =
-                new Notification.Action[] { createContextualAction("appGeneratedAction") };
-
-        ArrayList<Notification.Action> systemGeneratedSmartActions =
-                createActions("systemGeneratedAction");
-
-        SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
-        ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
-        snoozeCriterions.add(snoozeCriterion);
-
-        Ranking ranking = new RankingBuilder()
-                .setKey(sbn.getKey())
-                .setSmartActions(systemGeneratedSmartActions)
-                .setChannel(NOTIFICATION_CHANNEL)
-                .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
-                .setSnoozeCriteria(snoozeCriterions)
-                .build();
-
-        NotificationEntry entry =
-                new NotificationEntry(sbn, ranking);
-
-        assertEquals(systemGeneratedSmartActions, entry.getSmartActions());
-        assertEquals(NOTIFICATION_CHANNEL, entry.getChannel());
-        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment());
-        assertEquals(snoozeCriterions, entry.getSnoozeCriteria());
-    }
-
-    @Test
-    public void notificationDataEntry_testIsLastMessageFromReply() {
-        Person.Builder person = new Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true);
-
-        // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
-        Bundle[] messagesBundle = new Bundle[]{ new Notification.MessagingStyle.Message(
-                "text", 0, person.build()).toBundle() };
-        bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
-
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addExtras(bundle)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(notification)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-        entry.setHasSentReply();
-
-        assertTrue(entry.isLastMessageFromReply());
-    }
-
-    @Test
-    public void personHighPriority() {
-        Person person = new Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true)
-                .build();
-
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addPerson(person)
-                .build();
-
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        assertTrue(mNotificationData.isHighPriority(sbn));
-    }
-
-    @Test
-    public void messagingStyleHighPriority() {
-
-        Notification notification = new Notification.Builder(mContext, "test")
-                .setStyle(new Notification.MessagingStyle(""))
-                .build();
-
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        assertTrue(mNotificationData.isHighPriority(sbn));
-    }
-
-    @Test
-    public void minForegroundNotHighPriority() {
-        Notification notification = mock(Notification.class);
-        when(notification.isForegroundService()).thenReturn(true);
-
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
-        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
-        assertFalse(mNotificationData.isHighPriority(sbn));
-    }
-
-    @Test
-    public void lowForegroundHighPriority() {
-        Notification notification = mock(Notification.class);
-        when(notification.isForegroundService()).thenReturn(true);
-
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
-        assertTrue(mNotificationData.isHighPriority(sbn));
-    }
-
-    @Test
-    public void userChangeTrumpsHighPriorityCharacteristics() {
-        Person person = new Person.Builder()
-                .setName("name")
-                .setKey("abc")
-                .setUri("uri")
-                .setBot(true)
-                .build();
-
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addPerson(person)
-                .setStyle(new Notification.MessagingStyle(""))
-                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
-                .build();
-
-        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
-                notification, mContext.getUser(), "", 0);
-
-        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW);
-        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-
-        Bundle override = new Bundle();
-        override.putParcelable(OVERRIDE_CHANNEL, channel);
-        mNotificationData.rankingOverrides.put(sbn.getKey(), override);
-
-        assertFalse(mNotificationData.isHighPriority(sbn));
-    }
-
-    @Test
-    public void testSort_highPriorityTrumpsNMSRank() {
-        // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
-        // front
-        Notification aN = new Notification.Builder(mContext, "test")
-                .setStyle(new Notification.MessagingStyle(""))
-                .build();
-        NotificationEntry a = new NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-        a.setRow(mock(ExpandableNotificationRow.class));
-        a.setIsHighPriority(false);
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        override.putInt(OVERRIDE_RANK, 1);
-        mNotificationData.rankingOverrides.put(a.getKey(), override);
-
-        Notification bN = new Notification.Builder(mContext, "test")
-                .setStyle(new Notification.MessagingStyle(""))
-                .build();
-        NotificationEntry b = new NotificationEntryBuilder()
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-        b.setIsHighPriority(true);
-        b.setRow(mock(ExpandableNotificationRow.class));
-
-        Bundle bOverride = new Bundle();
-        bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        bOverride.putInt(OVERRIDE_RANK, 2);
-        mNotificationData.rankingOverrides.put(b.getKey(), bOverride);
-
-        assertEquals(1, mNotificationData.mRankingComparator.compare(a, b));
-    }
-
-    @Test
-    public void testSort_samePriorityUsesNMSRank() {
-        // NMS rank says A and then B, and they are the same priority so use that rank
-        Notification aN = new Notification.Builder(mContext, "test")
-                .setStyle(new Notification.MessagingStyle(""))
-                .build();
-        NotificationEntry a = new NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(aN)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-        a.setRow(mock(ExpandableNotificationRow.class));
-        a.setIsHighPriority(false);
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        override.putInt(OVERRIDE_RANK, 1);
-        mNotificationData.rankingOverrides.put(a.getKey(), override);
-
-        Notification bN = new Notification.Builder(mContext, "test")
-                .setStyle(new Notification.MessagingStyle(""))
-                .build();
-        NotificationEntry b = new NotificationEntryBuilder()
-                .setPkg("pkg2")
-                .setOpPkg("pkg2")
-                .setTag("tag")
-                .setNotification(bN)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-        b.setRow(mock(ExpandableNotificationRow.class));
-        b.setIsHighPriority(false);
-
-        Bundle bOverride = new Bundle();
-        bOverride.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        bOverride.putInt(OVERRIDE_RANK, 2);
-        mNotificationData.rankingOverrides.put(b.getKey(), bOverride);
-
-        assertEquals(-1, mNotificationData.mRankingComparator.compare(a, b));
-    }
-
-    @Test
-    public void testSort_properlySetsAlertingBucket() {
-        Notification notification = new Notification.Builder(mContext, "test")
-                .build();
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(notification)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_DEFAULT);
-        mNotificationData.rankingOverrides.put(entry.getKey(), override);
-
-        entry.setRow(mRow);
-        mNotificationData.add(entry);
-
-        assertEquals(entry.getBucket(), BUCKET_ALERTING);
-    }
-
-    @Test
-    public void testSort_properlySetsSilentBucket() {
-        Notification notification = new Notification.Builder(mContext, "test")
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg("pkg")
-                .setOpPkg("pkg")
-                .setTag("tag")
-                .setNotification(notification)
-                .setUser(mContext.getUser())
-                .setOverrideGroupKey("")
-                .build();
-
-        Bundle override = new Bundle();
-        override.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
-        mNotificationData.rankingOverrides.put(entry.getKey(), override);
-
-        entry.setRow(mRow);
-        mNotificationData.add(entry);
-
-        assertEquals(entry.getBucket(), BUCKET_SILENT);
-    }
-
-    private void initStatusBarNotification(boolean allowDuringSetup) {
-        Bundle bundle = new Bundle();
-        bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
-        Notification notification = new Notification.Builder(mContext, "test")
-                .addExtras(bundle)
-                .build();
-        modifySbn(mEntry)
-                .setNotification(notification)
-                .build();
-    }
-
-    public static class TestableNotificationData extends NotificationData {
-        public TestableNotificationData(NotificationSectionsFeatureManager sectionsFeatureManager) {
-            super(
-                    sectionsFeatureManager,
-                    mock(NotifLog.class),
-                    mock(PeopleNotificationIdentifier.class));
-        }
-
-        public static final String OVERRIDE_RANK = "r";
-        public static final String OVERRIDE_DND = "dnd";
-        public static final String OVERRIDE_VIS_OVERRIDE = "vo";
-        public static final String OVERRIDE_VIS_EFFECTS = "ve";
-        public static final String OVERRIDE_IMPORTANCE = "i";
-        public static final String OVERRIDE_IMP_EXP = "ie";
-        public static final String OVERRIDE_GROUP = "g";
-        public static final String OVERRIDE_CHANNEL = "c";
-        public static final String OVERRIDE_PEOPLE = "p";
-        public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
-        public static final String OVERRIDE_BADGE = "b";
-        public static final String OVERRIDE_USER_SENTIMENT = "us";
-        public static final String OVERRIDE_HIDDEN = "h";
-        public static final String OVERRIDE_LAST_ALERTED = "la";
-        public static final String OVERRIDE_NOISY = "n";
-        public static final String OVERRIDE_SMART_ACTIONS = "sa";
-        public static final String OVERRIDE_SMART_REPLIES = "sr";
-        public static final String OVERRIDE_BUBBLE = "cb";
-        public static final String OVERRIDE_VISUALLY_INTERRUPTIVE = "vi";
-
-        public Map<String, Bundle> rankingOverrides = new HashMap<>();
-
-        @Override
-        protected boolean getRanking(String key, Ranking outRanking) {
-            super.getRanking(key, outRanking);
-
-            ArrayList<String> currentAdditionalPeople = new ArrayList<>();
-            if (outRanking.getAdditionalPeople() != null) {
-                currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
-            }
-
-            ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
-            if (outRanking.getSnoozeCriteria() != null) {
-                currentSnooze.addAll(outRanking.getSnoozeCriteria());
-            }
-
-            ArrayList<Notification.Action> currentActions = new ArrayList<>();
-            if (outRanking.getSmartActions() != null) {
-                currentActions.addAll(outRanking.getSmartActions());
-            }
-
-            ArrayList<CharSequence> currentReplies = new ArrayList<>();
-            if (outRanking.getSmartReplies() != null) {
-                currentReplies.addAll(outRanking.getSmartReplies());
-            }
-
-            if (rankingOverrides.get(key) != null) {
-                Bundle overrides = rankingOverrides.get(key);
-                outRanking.populate(key,
-                        overrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
-                        overrides.getBoolean(OVERRIDE_DND, outRanking.matchesInterruptionFilter()),
-                        overrides.getInt(OVERRIDE_VIS_OVERRIDE, outRanking.getVisibilityOverride()),
-                        overrides.getInt(OVERRIDE_VIS_EFFECTS,
-                                outRanking.getSuppressedVisualEffects()),
-                        overrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
-                        overrides.getCharSequence(OVERRIDE_IMP_EXP,
-                                outRanking.getImportanceExplanation()),
-                        overrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
-                        overrides.containsKey(OVERRIDE_CHANNEL)
-                                ? (NotificationChannel) overrides.getParcelable(OVERRIDE_CHANNEL)
-                                : outRanking.getChannel(),
-                        overrides.containsKey(OVERRIDE_PEOPLE)
-                                ? overrides.getStringArrayList(OVERRIDE_PEOPLE)
-                                : currentAdditionalPeople,
-                        overrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
-                                ? overrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
-                                : currentSnooze,
-                        overrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
-                        overrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
-                        overrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
-                        overrides.getLong(OVERRIDE_LAST_ALERTED,
-                                outRanking.getLastAudiblyAlertedMillis()),
-                        overrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
-                        overrides.containsKey(OVERRIDE_SMART_ACTIONS)
-                                ? overrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
-                                : currentActions,
-                        overrides.containsKey(OVERRIDE_SMART_REPLIES)
-                                ? overrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
-                                : currentReplies,
-                        overrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()),
-                        overrides.getBoolean(OVERRIDE_VISUALLY_INTERRUPTIVE,
-                                outRanking.visuallyInterruptive()));
-            } else {
-                outRanking.populate(
-                        new RankingBuilder()
-                                .setKey(key)
-                                .build());
-            }
-            return true;
-        }
-    }
-
-    private Notification.Action createContextualAction(String title) {
-        return new Notification.Action.Builder(
-                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
-                title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
-                        .setContextual(true)
-                        .build();
-    }
-
-    private Notification.Action createAction(String title) {
-        return new Notification.Action.Builder(
-                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
-                title,
-                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
-    }
-
-    private ArrayList<Notification.Action> createActions(String... titles) {
-        ArrayList<Notification.Action> actions = new ArrayList<>();
-        for (String title : titles) {
-            actions.add(createAction(title));
-        }
-        return actions;
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
new file mode 100644
index 0000000..536aeb4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static android.app.Notification.CATEGORY_ALARM;
+import static android.app.Notification.CATEGORY_CALL;
+import static android.app.Notification.CATEGORY_EVENT;
+import static android.app.Notification.CATEGORY_MESSAGE;
+import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
+import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.PendingIntent;
+import android.app.Person;
+import android.content.Intent;
+import android.graphics.drawable.Icon;
+import android.media.session.MediaSession;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.service.notification.NotificationListenerService.Ranking;
+import android.service.notification.SnoozeCriterion;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
+import com.android.systemui.statusbar.RankingBuilder;
+import com.android.systemui.statusbar.SbnBuilder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class NotificationEntryTest extends SysuiTestCase {
+    private static final String TEST_PACKAGE_NAME = "test";
+    private static final int TEST_UID = 0;
+    private static final int UID_NORMAL = 123;
+    private static final NotificationChannel NOTIFICATION_CHANNEL =
+            new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
+
+    private int mId;
+
+    private NotificationEntry mEntry;
+
+    @Before
+    public void setup() {
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+
+        mEntry = new NotificationEntryBuilder()
+                .setPkg(TEST_PACKAGE_NAME)
+                .setOpPkg(TEST_PACKAGE_NAME)
+                .setUid(TEST_UID)
+                .setId(mId++)
+                .setNotification(n.build())
+                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
+                .build();
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_foreground() {
+        mEntry.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
+
+        assertTrue(mEntry.isExemptFromDndVisualSuppression());
+        assertFalse(mEntry.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_media() {
+        Notification.Builder n = new Notification.Builder(mContext, "")
+                .setStyle(new Notification.MediaStyle()
+                        .setMediaSession(mock(MediaSession.Token.class)))
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle("Title")
+                .setContentText("Text");
+        NotificationEntry e1 = new NotificationEntryBuilder()
+                .setNotification(n.build())
+                .build();
+
+        assertTrue(e1.isExemptFromDndVisualSuppression());
+        assertFalse(e1.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsExemptFromDndVisualSuppression_system() {
+        mEntry.mIsSystemNotification = true;
+
+        assertTrue(mEntry.isExemptFromDndVisualSuppression());
+        assertFalse(mEntry.shouldSuppressAmbient());
+    }
+
+    @Test
+    public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setUid(UID_NORMAL)
+                .build();
+        entry.mIsSystemNotification = true;
+        modifyRanking(entry).setSuppressedVisualEffects(SUPPRESSED_EFFECT_AMBIENT).build();
+
+        modifySbn(entry)
+                .setNotification(
+                        new Notification.Builder(mContext, "").setCategory(CATEGORY_CALL).build())
+                .build();
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+        assertTrue(entry.shouldSuppressAmbient());
+
+        modifySbn(entry)
+                .setNotification(
+                        new Notification.Builder(mContext, "")
+                                .setCategory(CATEGORY_REMINDER)
+                                .build())
+                .build();
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        modifySbn(entry)
+                .setNotification(
+                        new Notification.Builder(mContext, "").setCategory(CATEGORY_ALARM).build())
+                .build();
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        modifySbn(entry)
+                .setNotification(
+                        new Notification.Builder(mContext, "").setCategory(CATEGORY_EVENT).build())
+                .build();
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+
+        modifySbn(entry)
+                .setNotification(
+                        new Notification.Builder(mContext, "")
+                                .setCategory(CATEGORY_MESSAGE)
+                                .build())
+                .build();
+        assertFalse(entry.isExemptFromDndVisualSuppression());
+    }
+
+    @Test
+    public void testCreateNotificationDataEntry_RankingUpdate() {
+        StatusBarNotification sbn = new SbnBuilder().build();
+        sbn.getNotification().actions =
+                new Notification.Action[]{createContextualAction("appGeneratedAction")};
+
+        ArrayList<Notification.Action> systemGeneratedSmartActions =
+                createActions("systemGeneratedAction");
+
+        SnoozeCriterion snoozeCriterion = new SnoozeCriterion("id", "explanation", "confirmation");
+        ArrayList<SnoozeCriterion> snoozeCriterions = new ArrayList<>();
+        snoozeCriterions.add(snoozeCriterion);
+
+        Ranking ranking = new RankingBuilder()
+                .setKey(sbn.getKey())
+                .setSmartActions(systemGeneratedSmartActions)
+                .setChannel(NOTIFICATION_CHANNEL)
+                .setUserSentiment(Ranking.USER_SENTIMENT_NEGATIVE)
+                .setSnoozeCriteria(snoozeCriterions)
+                .build();
+
+        NotificationEntry entry =
+                new NotificationEntry(sbn, ranking);
+
+        assertEquals(systemGeneratedSmartActions, entry.getSmartActions());
+        assertEquals(NOTIFICATION_CHANNEL, entry.getChannel());
+        assertEquals(Ranking.USER_SENTIMENT_NEGATIVE, entry.getUserSentiment());
+        assertEquals(snoozeCriterions, entry.getSnoozeCriteria());
+    }
+
+    @Test
+    public void notificationDataEntry_testIsLastMessageFromReply() {
+        Person.Builder person = new Person.Builder()
+                .setName("name")
+                .setKey("abc")
+                .setUri("uri")
+                .setBot(true);
+
+        // EXTRA_MESSAGING_PERSON is the same Person as the sender in last message in EXTRA_MESSAGES
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person.build());
+        Bundle[] messagesBundle = new Bundle[]{new Notification.MessagingStyle.Message(
+                "text", 0, person.build()).toBundle()};
+        bundle.putParcelableArray(Notification.EXTRA_MESSAGES, messagesBundle);
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addExtras(bundle)
+                .build();
+
+        NotificationEntry entry = new NotificationEntryBuilder()
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(notification)
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build();
+        entry.setHasSentReply();
+
+        assertTrue(entry.isLastMessageFromReply());
+    }
+
+    private Notification.Action createContextualAction(String title) {
+        return new Notification.Action.Builder(
+                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+                title,
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0))
+                .setContextual(true)
+                .build();
+    }
+
+    private Notification.Action createAction(String title) {
+        return new Notification.Action.Builder(
+                Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
+                title,
+                PendingIntent.getBroadcast(getContext(), 0, new Intent("Action"), 0)).build();
+    }
+
+    private ArrayList<Notification.Action> createActions(String... titles) {
+        ArrayList<Notification.Action> actions = new ArrayList<>();
+        for (String title : titles) {
+            actions.add(createAction(title));
+        }
+        return actions;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
new file mode 100644
index 0000000..01b2f89
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager.IMPORTANCE_DEFAULT
+import android.app.NotificationManager.IMPORTANCE_LOW
+import android.app.Person
+import android.service.notification.NotificationListenerService.RankingMap
+import android.service.notification.StatusBarNotification
+import android.testing.AndroidTestingRunner
+
+import org.junit.runner.RunWith
+
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.NotificationEntryBuilder
+import com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.notification.NotificationFilter
+import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager
+import com.android.systemui.statusbar.notification.logging.NotifLog
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING
+import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import dagger.Lazy
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
+
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class NotificationRankingManagerTest
+    : SysuiTestCase() {
+
+    private var lazyMedia: Lazy<NotificationMediaManager> = Lazy {
+        mock<NotificationMediaManager>(NotificationMediaManager::class.java)
+    }
+
+    private val rankingManager = TestableNotificationRankingManager(
+            lazyMedia,
+            mock<NotificationGroupManager>(NotificationGroupManager::class.java),
+            mock<HeadsUpManager>(HeadsUpManager::class.java),
+            mock<NotificationFilter>(NotificationFilter::class.java),
+            mock<NotifLog>(NotifLog::class.java),
+            mock<NotificationSectionsFeatureManager>(NotificationSectionsFeatureManager::class.java)
+    )
+
+    @Before
+    fun setup() {
+    }
+
+    @Test
+    fun testPeopleNotification_isHighPriority() {
+        val person = Person.Builder()
+                .setName("name")
+                .setKey("abc")
+                .setUri("uri")
+                .setBot(true)
+                .build()
+
+        val notification = Notification.Builder(mContext, "test")
+                .addPerson(person)
+                .build()
+
+        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.user, "", 0)
+
+        val e = NotificationEntryBuilder()
+                .setNotification(notification)
+                .setSbn(sbn)
+                .build()
+
+        assertTrue(rankingManager.isHighPriority2(e))
+    }
+
+    @Test
+    fun messagingStyleHighPriority() {
+
+        val notif = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+
+        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notif, mContext.getUser(), "", 0)
+
+        val e = NotificationEntryBuilder()
+                .setNotification(notif)
+                .setSbn(sbn)
+                .build()
+
+        assertTrue(rankingManager.isHighPriority2(e))
+    }
+
+    @Test
+    fun lowForegroundHighPriority() {
+        val notification = mock(Notification::class.java)
+        `when`<Boolean>(notification.isForegroundService).thenReturn(true)
+
+        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.user, "", 0)
+
+        val e = NotificationEntryBuilder()
+                .setNotification(notification)
+                .setSbn(sbn)
+                .build()
+
+        modifyRanking(e)
+                .setImportance(IMPORTANCE_LOW)
+                .build()
+
+        assertTrue(rankingManager.isHighPriority2(e))
+    }
+
+    @Test
+    fun userChangeTrumpsHighPriorityCharacteristics() {
+        val person = Person.Builder()
+                .setName("name")
+                .setKey("abc")
+                .setUri("uri")
+                .setBot(true)
+                .build()
+
+        val notification = Notification.Builder(mContext, "test")
+                .addPerson(person)
+                .setStyle(Notification.MessagingStyle(""))
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .build()
+
+        val sbn = StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.user, "", 0)
+
+        val channel = NotificationChannel("a", "a", IMPORTANCE_LOW)
+        channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE)
+
+        val e = NotificationEntryBuilder()
+                .setSbn(sbn)
+                .setChannel(channel)
+                .build()
+
+        assertFalse(rankingManager.isHighPriority2(e))
+    }
+
+    @Test
+    fun testSort_highPriorityTrumpsNMSRank() {
+        // NMS rank says A and then B. But A is not high priority and B is, so B should sort in
+        // front
+        val aN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val a = NotificationEntryBuilder()
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(aN)
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+
+        a.setIsHighPriority(false)
+
+        modifyRanking(a)
+                .setImportance(IMPORTANCE_LOW)
+                .setRank(1)
+                .build()
+
+        val bN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val b = NotificationEntryBuilder()
+                .setPkg("pkg2")
+                .setOpPkg("pkg2")
+                .setTag("tag")
+                .setNotification(bN)
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+        b.setIsHighPriority(true)
+
+        modifyRanking(b)
+                .setImportance(IMPORTANCE_LOW)
+                .setRank(2)
+                .build()
+
+        assertEquals(
+                listOf(b, a),
+                rankingManager.updateRanking(null, listOf(a, b), "test"))
+    }
+
+    @Test
+    fun testSort_samePriorityUsesNMSRank() {
+        // NMS rank says A and then B, and they are the same priority so use that rank
+        val aN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val a = NotificationEntryBuilder()
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(aN)
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+        a.setIsHighPriority(false)
+
+        modifyRanking(a)
+                .setImportance(IMPORTANCE_LOW)
+                .setRank(1)
+                .build()
+
+        val bN = Notification.Builder(mContext, "test")
+                .setStyle(Notification.MessagingStyle(""))
+                .build()
+        val b = NotificationEntryBuilder()
+                .setPkg("pkg2")
+                .setOpPkg("pkg2")
+                .setTag("tag")
+                .setNotification(bN)
+                .setUser(mContext.getUser())
+                .setOverrideGroupKey("")
+                .build()
+        b.setIsHighPriority(false)
+
+        modifyRanking(b)
+                .setImportance(IMPORTANCE_LOW)
+                .setRank(2)
+                .build()
+
+        assertEquals(
+                listOf(a, b),
+                rankingManager.updateRanking(null, listOf(a, b), "test"))
+    }
+
+    @Test
+    fun testSort_properlySetsAlertingBucket() {
+        val notif = Notification.Builder(mContext, "test") .build()
+
+        val e = NotificationEntryBuilder()
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(notif)
+                .setUser(mContext.user)
+                .setOverrideGroupKey("")
+                .build()
+
+        modifyRanking(e).setImportance(IMPORTANCE_DEFAULT) .build()
+
+        rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
+        assertEquals(e.bucket, BUCKET_ALERTING)
+    }
+
+    @Test
+    fun testSort_properlySetsSilentBucket() {
+        val notif = Notification.Builder(mContext, "test") .build()
+
+        val e = NotificationEntryBuilder()
+                .setPkg("pkg")
+                .setOpPkg("pkg")
+                .setTag("tag")
+                .setNotification(notif)
+                .setUser(mContext.user)
+                .setOverrideGroupKey("")
+                .build()
+
+        modifyRanking(e).setImportance(IMPORTANCE_LOW).build()
+
+        rankingManager.updateRanking(RankingMap(arrayOf(e.ranking)), listOf(e), "test")
+        assertEquals(e.bucket, BUCKET_SILENT)
+    }
+
+    internal class TestableNotificationRankingManager(
+        mediaManager: Lazy<NotificationMediaManager>,
+        groupManager: NotificationGroupManager,
+        headsUpManager: HeadsUpManager,
+        filter: NotificationFilter,
+        notifLog: NotifLog,
+        sectionsFeatureManager: NotificationSectionsFeatureManager
+    ) : NotificationRankingManager(
+        mediaManager,
+        groupManager,
+        headsUpManager,
+        filter,
+        notifLog,
+        sectionsFeatureManager
+    ) {
+
+        fun isHighPriority2(e: NotificationEntry): Boolean {
+            return isHighPriority(e)
+        }
+
+        fun applyTestRankingMap(r: RankingMap) {
+            rankingMap = r
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
index 2b343c2..4f1ffbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/ExpansionStateLoggerTest.java
@@ -158,7 +158,7 @@
     }
 
     @Test
-    public void testOnEntryReinflated() throws RemoteException {
+    public void testOnEntryUpdated() throws RemoteException {
         mLogger.onExpansionChanged(NOTIFICATION_KEY, true, true,
                 NotificationVisibility.NotificationLocation.LOCATION_UNKNOWN);
         mLogger.onVisibilityChanged(
@@ -168,7 +168,7 @@
         verify(mBarService).onNotificationExpansionChanged(
                 NOTIFICATION_KEY, true, true, ExpandableViewState.LOCATION_UNKNOWN);
 
-        mLogger.onEntryReinflated(NOTIFICATION_KEY);
+        mLogger.onEntryUpdated(NOTIFICATION_KEY);
         mLogger.onVisibilityChanged(
                 Collections.singletonList(createNotificationVisibility(NOTIFICATION_KEY, true)),
                 Collections.emptyList());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index 47c17ad..d139866 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -44,7 +44,6 @@
 import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -71,7 +70,6 @@
 
     @Mock private NotificationListContainer mListContainer;
     @Mock private IStatusBarService mBarService;
-    @Mock private NotificationData mNotificationData;
     @Mock private ExpandableNotificationRow mRow;
     @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
 
@@ -91,8 +89,6 @@
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         mDependency.injectTestDependency(NotificationListener.class, mListener);
 
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-
         mEntry = new NotificationEntryBuilder()
                 .setPkg(TEST_PACKAGE_NAME)
                 .setOpPkg(TEST_PACKAGE_NAME)
@@ -131,7 +127,7 @@
                 any(NotificationVisibility[].class));
 
         when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
-        when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
+        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
         mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
         TestableLooper.get(this).processAllMessages();
         waitForUiOffloadThread();
@@ -153,7 +149,7 @@
     public void testStoppingNotificationLoggingReportsCurrentNotifications()
             throws Exception {
         when(mListContainer.isInVisibleLocation(any())).thenReturn(true);
-        when(mNotificationData.getActiveNotifications()).thenReturn(Lists.newArrayList(mEntry));
+        when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
         mLogger.getChildLocationsChangedListenerForTest().onChildLocationsChanged();
         TestableLooper.get(this).processAllMessages();
         waitForUiOffloadThread();
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 c7877bb..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
@@ -121,10 +121,10 @@
         mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager);
         mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
         mHandler = Handler.createAsync(mTestableLooper.getLooper());
-        mContext.putComponent(StatusBar.class, mStatusBar);
         mHelper = new NotificationTestHelper(mContext, mDependency);
 
-        mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager);
+        mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager,
+                () -> mStatusBar);
         mGutsManager.setUpWithPresenter(mPresenter, mStackScroller,
                 mCheckSaveListener, mOnSettingsClickListener);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
@@ -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/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 6f52e4a..5b624bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -20,7 +20,6 @@
 import static junit.framework.Assert.assertNull;
 
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -56,7 +55,9 @@
 import com.android.systemui.classifier.FalsingManagerFake;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.statusbar.EmptyShadeView;
+import com.android.systemui.statusbar.NotificationEntryBuilder;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
@@ -65,9 +66,13 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.NotificationFilter;
 import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.TestableNotificationEntryManager;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
+import com.android.systemui.statusbar.notification.logging.NotifLog;
 import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.FooterView;
@@ -80,7 +85,6 @@
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.util.DeviceConfigProxyFake;
@@ -97,6 +101,7 @@
 import org.mockito.junit.MockitoRule;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Tests for {@link NotificationStackScrollLayout}.
@@ -117,7 +122,6 @@
     @Mock private NotificationGroupManager mGroupManager;
     @Mock private ExpandHelper mExpandHelper;
     @Mock private EmptyShadeView mEmptyShadeView;
-    @Mock private NotificationData mNotificationData;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
     @Mock private NotificationIconAreaController mNotificationIconAreaController;
@@ -140,6 +144,7 @@
                 NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
 
         // Inject dependencies before initializing the layout
+        mDependency.injectMockDependency(VisualStabilityManager.class);
         mDependency.injectTestDependency(
                 NotificationBlockingHelperManager.class,
                 mBlockingHelperManager);
@@ -150,7 +155,18 @@
         mDependency.injectMockDependency(ShadeController.class);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
 
-        mEntryManager = new TestableNotificationEntryManager(mNotificationData);
+        mEntryManager = new TestableNotificationEntryManager(
+                mock(NotifLog.class),
+                mock(NotificationGroupManager.class),
+                new NotificationRankingManager(
+                        () -> mock(NotificationMediaManager.class),
+                        mGroupManager,
+                        mHeadsUpManager,
+                        mock(NotificationFilter.class),
+                        mock(NotifLog.class),
+                        mock(NotificationSectionsFeatureManager.class)
+                ),
+                mock(NotificationEntryManager.KeyguardEnvironment.class));
         mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
         Dependency.get(InitController.class).executePostInitTasks();
         mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, mHeadsUpManager);
@@ -161,8 +177,8 @@
         // The actual class under test.  You may need to work with this class directly when
         // testing anonymous class members of mStackScroller, like mMenuEventListener,
         // which refer to members of NotificationStackScrollLayout. The spy
-        // holds a copy of the CUT's instances of these classes, so they still refer to the CUT's
-        // member variables, not the spy's member variables.
+        // holds a copy of the CUT's instances of these KeyguardBypassController, so they still
+        // refer to the CUT's member variables, not the spy's member variables.
         mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null,
                 true /* allowLongPress */, mNotificationRoundnessManager,
                 mock(DynamicPrivacyController.class),
@@ -293,7 +309,7 @@
     @Test
     public void testUpdateFooter_noNotifications() {
         setBarStateForTest(StatusBarState.SHADE);
-        assertEquals(0, mNotificationData.getActiveNotifications().size());
+        assertEquals(0, mEntryManager.getActiveNotificationsCount());
 
         mStackScroller.updateFooter();
         verify(mStackScroller, atLeastOnce()).updateFooterView(false, false);
@@ -303,8 +319,8 @@
     public void testUpdateFooter_remoteInput() {
         setBarStateForTest(StatusBarState.SHADE);
         ArrayList<NotificationEntry> entries = new ArrayList<>();
-        entries.add(mock(NotificationEntry.class));
-        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+        entries.add(new NotificationEntryBuilder().build());
+        addEntriesToEntryManager(entries);
 
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
         when(row.canViewBeDismissed()).thenReturn(true);
@@ -319,9 +335,10 @@
     @Test
     public void testUpdateFooter_oneClearableNotification() {
         setBarStateForTest(StatusBarState.SHADE);
+
         ArrayList<NotificationEntry> entries = new ArrayList<>();
-        entries.add(mock(NotificationEntry.class));
-        when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+        entries.add(new NotificationEntryBuilder().build());
+        addEntriesToEntryManager(entries);
 
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
         when(row.canViewBeDismissed()).thenReturn(true);
@@ -335,10 +352,10 @@
     @Test
     public void testUpdateFooter_oneNonClearableNotification() {
         setBarStateForTest(StatusBarState.SHADE);
+
         ArrayList<NotificationEntry> entries = new ArrayList<>();
-        entries.add(mock(NotificationEntry.class));
-        when(mEntryManager.getNotificationData().getActiveNotifications()).thenReturn(entries);
-        assertTrue(mEntryManager.getNotificationData().getActiveNotifications().size() != 0);
+        entries.add(new NotificationEntryBuilder().build());
+        addEntriesToEntryManager(entries);
 
         mStackScroller.updateFooter();
         verify(mStackScroller).updateFooterView(true, false);
@@ -460,4 +477,14 @@
         // rather than the mock because the spy just coppied the anonymous inner /shruggie.
         mStackScroller.setStatusBarState(state);
     }
+
+    private void addEntriesToEntryManager(List<NotificationEntry> entries) {
+        for (NotificationEntry e : entries) {
+            mEntryManager.addActiveNotificationForTest(e);
+        }
+    }
+
+    private void addActiveNotificationsToManager(List<NotificationEntry> entries) {
+        mEntryManager.setActiveNotificationList(entries);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index 88ed80a..8decae3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -34,8 +34,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiBaseFragmentTest;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.tuner.TunerService;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -58,10 +56,8 @@
 
     @Before
     public void setup() {
-        mSysuiContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         StatusBar statusBar = mock(StatusBar.class);
-        mSysuiContext.putComponent(StatusBar.class, statusBar);
-        mSysuiContext.putComponent(TunerService.class, mock(TunerService.class));
+        mDependency.injectTestDependency(StatusBar.class, statusBar);
         mStatusBarStateController = mDependency
                 .injectMockDependency(StatusBarStateController.class);
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
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 b05172c..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
@@ -60,8 +60,6 @@
 import java.util.Collections;
 import java.util.HashSet;
 
-import dagger.Lazy;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class DozeServiceHostTest extends SysuiTestCase {
@@ -71,7 +69,6 @@
     @Mock private HeadsUpManagerPhone mHeadsUpManager;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
-    @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private KeyguardViewMediator mKeyguardViewMediator;
     @Mock private StatusBarStateControllerImpl mStatusBarStateController;
@@ -97,13 +94,12 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        when(mBiometricUnlockControllerLazy.get()).thenReturn(mBiometricUnlockController);
         mDozeServiceHost = new DozeServiceHost(mDozeLog, mPowerManager, mWakefullnessLifecycle,
                 mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
-                mBatteryController, mScrimController, mBiometricUnlockControllerLazy,
-                mKeyguardViewMediator, mAssistManager, mDozeScrimController, mKeyguardUpdateMonitor,
-                mVisualStabilityManager, mPulseExpansionHandler, mStatusBarWindowController,
-                mNotificationWakeUpCoordinator);
+                mBatteryController, mScrimController, () -> mBiometricUnlockController,
+                mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
+                mKeyguardUpdateMonitor, mVisualStabilityManager, mPulseExpansionHandler,
+                mStatusBarWindowController, mNotificationWakeUpCoordinator);
 
         mDozeServiceHost.initialize(mStatusBar, mNotificationIconAreaController,
                 mStatusBarWindowViewController, mStatusBarWindow, mStatusBarKeyguardViewManager,
@@ -162,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/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
index 64c1b51..a024454 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
@@ -40,7 +40,6 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
 import org.junit.Before;
@@ -51,8 +50,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import java.util.ArrayList;
-
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -61,7 +58,6 @@
     private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS;
 
     @Mock private NotificationEntryManager mEntryManager;
-    @Mock private NotificationData mNotificationData;
     @Mock private CommandQueue mCommandQueue;
     @Mock private WindowManager mWindowManager;
     @Mock private Display mDisplay;
@@ -71,7 +67,6 @@
 
     private View mLightsOutView;
     private LightsOutNotifController mLightsOutNotifController;
-    private ArrayList<NotificationEntry> mActiveNotifications = new ArrayList<>();
     private int mDisplayId;
     private NotificationEntryListener mEntryListener;
     private CommandQueue.Callbacks mCallbacks;
@@ -81,8 +76,6 @@
         MockitoAnnotations.initMocks(this);
         mDisplayId = mContext.getDisplayId();
         mLightsOutView = new View(mContext);
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
-        when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications);
         when(mWindowManager.getDefaultDisplay()).thenReturn(mDisplay);
         when(mDisplay.getDisplayId()).thenReturn(mDisplayId);
 
@@ -136,7 +129,7 @@
     @Test
     public void testLightsOut_withNotifs_onSystemBarAppearanceChanged() {
         // GIVEN active visible notifications
-        mActiveNotifications.add(mock(NotificationEntry.class));
+        when(mEntryManager.hasActiveNotifications()).thenReturn(true);
 
         // WHEN lights out
         mCallbacks.onSystemBarAppearanceChanged(
@@ -153,7 +146,7 @@
     @Test
     public void testLightsOut_withoutNotifs_onSystemBarAppearanceChanged() {
         // GIVEN no active visible notifications
-        mActiveNotifications.clear();
+        when(mEntryManager.hasActiveNotifications()).thenReturn(false);
 
         // WHEN lights out
         mCallbacks.onSystemBarAppearanceChanged(
@@ -170,7 +163,7 @@
     @Test
     public void testLightsOn_afterLightsOut_onSystemBarAppearanceChanged() {
         // GIVEN active visible notifications
-        mActiveNotifications.add(mock(NotificationEntry.class));
+        when(mEntryManager.hasActiveNotifications()).thenReturn(true);
 
         // WHEN lights on
         mCallbacks.onSystemBarAppearanceChanged(
@@ -187,13 +180,13 @@
     @Test
     public void testEntryAdded() {
         // GIVEN no visible notifications and lights out
-        mActiveNotifications.clear();
+        when(mEntryManager.hasActiveNotifications()).thenReturn(false);
         mLightsOutNotifController.mAppearance = LIGHTS_OUT;
         mLightsOutNotifController.updateLightsOutView();
         assertIsShowingDot(false);
 
         // WHEN an active notification is added
-        mActiveNotifications.add(mock(NotificationEntry.class));
+        when(mEntryManager.hasActiveNotifications()).thenReturn(true);
         assertTrue(mLightsOutNotifController.shouldShowDot());
         mEntryListener.onNotificationAdded(mock(NotificationEntry.class));
 
@@ -204,13 +197,13 @@
     @Test
     public void testEntryRemoved() {
         // GIVEN a visible notification and lights out
-        mActiveNotifications.add(mock(NotificationEntry.class));
+        when(mEntryManager.hasActiveNotifications()).thenReturn(true);
         mLightsOutNotifController.mAppearance = LIGHTS_OUT;
         mLightsOutNotifController.updateLightsOutView();
         assertIsShowingDot(true);
 
         // WHEN all active notifications are removed
-        mActiveNotifications.clear();
+        when(mEntryManager.hasActiveNotifications()).thenReturn(false);
         assertFalse(mLightsOutNotifController.shouldShowDot());
         mEntryListener.onEntryRemoved(mock(NotificationEntry.class), null, false);
 
@@ -221,13 +214,13 @@
     @Test
     public void testEntryUpdated() {
         // GIVEN no visible notifications and lights out
-        mActiveNotifications.clear();
+        when(mEntryManager.hasActiveNotifications()).thenReturn(false);
         mLightsOutNotifController.mAppearance = LIGHTS_OUT;
         mLightsOutNotifController.updateLightsOutView();
         assertIsShowingDot(false);
 
         // WHEN an active notification is added
-        mActiveNotifications.add(mock(NotificationEntry.class));
+        when(mEntryManager.hasActiveNotifications()).thenReturn(true);
         assertTrue(mLightsOutNotifController.shouldShowDot());
         mEntryListener.onPostEntryUpdated(mock(NotificationEntry.class));
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
index 098a69f..aae0757 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarButtonTest.java
@@ -18,7 +18,6 @@
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
 
 import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
@@ -37,7 +36,6 @@
 import com.android.systemui.SysuiTestableContext;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.After;
@@ -60,11 +58,9 @@
 
     @Before
     public void setup() {
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         final Display display = createVirtualDisplay();
         final SysuiTestableContext context =
                 (SysuiTestableContext) mContext.createDisplayContext(display);
-        context.putComponent(CommandQueue.class, mock(CommandQueue.class));
 
         mDependency.injectMockDependency(AssistManager.class);
         mDependency.injectMockDependency(OverviewProxyService.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
index 9763675..4e5ec1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -157,13 +157,10 @@
     }
 
     private void setupSysuiDependency() {
-        mSysuiContext.putComponent(StatusBar.class, mock(StatusBar.class));
-
         Display display = new Display(DisplayManagerGlobal.getInstance(), EXTERNAL_DISPLAY_ID,
                 new DisplayInfo(), DEFAULT_DISPLAY_ADJUSTMENTS);
         mSysuiTestableContextExternal = (SysuiTestableContext) mSysuiContext.createDisplayContext(
                 display);
-        mSysuiTestableContextExternal.putComponent(StatusBar.class, mock(StatusBar.class));
 
         injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES);
         WindowManager windowManager = mock(WindowManager.class);
@@ -255,7 +252,8 @@
                 mBroadcastDispatcher,
                 mCommandQueue,
                 mDivider,
-                Optional.of(mRecents));
+                Optional.of(mRecents),
+                () -> mock(StatusBar.class));
     }
 
     private class HostCallbacksForExternalDisplay extends
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java
index 991e495..80e33fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java
@@ -33,7 +33,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.After;
 import org.junit.Before;
@@ -52,7 +51,6 @@
 
     @Before
     public void setUp() {
-        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
         mDependency.injectMockDependency(AssistManager.class);
         mDependency.injectMockDependency(OverviewProxyService.class);
         mDependency.injectMockDependency(NavigationModeController.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 280cc90..c165e56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -54,11 +54,9 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
+import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
 import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -239,11 +237,10 @@
                     mock(ShadeController.class),
                     mock(NotificationLockscreenUserManager.class),
                     new NotificationEntryManager(
-                            new NotificationData(
-                                    mock(NotificationSectionsFeatureManager.class),
-                                    mock(NotifLog.class),
-                                    mock(PeopleNotificationIdentifier.class)),
-                            mock(NotifLog.class)),
+                            mock(NotifLog.class),
+                            mock(NotificationGroupManager.class),
+                            mock(NotificationRankingManager.class),
+                            mock(NotificationEntryManager.KeyguardEnvironment.class)),
                     mock(KeyguardStateController.class),
                     statusBarStateController,
                     mock(DozeLog.class),
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/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index d8a68b0..24a5d93 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -68,7 +68,6 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -117,7 +116,6 @@
     @Mock
     private Intent mContentIntentInner;
     @Mock
-    private NotificationData mNotificationData;
 
     private NotificationActivityStarter mNotificationActivityStarter;
 
@@ -134,7 +132,6 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
-        when(mEntryManager.getNotificationData()).thenReturn(mNotificationData);
 
         when(mContentIntent.isActivity()).thenReturn(true);
         when(mContentIntent.getCreatorUserHandle()).thenReturn(UserHandle.of(1));
@@ -157,7 +154,7 @@
         mActiveNotifications = new ArrayList<>();
         mActiveNotifications.add(mNotificationRow.getEntry());
         mActiveNotifications.add(mBubbleNotificationRow.getEntry());
-        when(mNotificationData.getActiveNotifications()).thenReturn(mActiveNotifications);
+        when(mEntryManager.getVisibleNotifications()).thenReturn(mActiveNotifications);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
 
         mNotificationActivityStarter = new StatusBarNotificationActivityStarter(getContext(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index de87d31..1c02b60 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -52,7 +52,6 @@
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -100,11 +99,9 @@
         mDependency.injectMockDependency(NotificationGutsManager.class);
         mDependency.injectMockDependency(StatusBarWindowController.class);
         mDependency.injectMockDependency(InitController.class);
-        NotificationData notificationData = mock(NotificationData.class);
-        when(notificationData.getNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
         NotificationEntryManager entryManager =
                 mDependency.injectMockDependency(NotificationEntryManager.class);
-        when(entryManager.getNotificationData()).thenReturn(notificationData);
+        when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
 
         StatusBarWindowView statusBarWindowView = mock(StatusBarWindowView.class);
         when(statusBarWindowView.getResources()).thenReturn(mContext.getResources());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 62fd0c5..1f2df65 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -89,6 +89,8 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.ScreenPinningRequest;
 import com.android.systemui.shared.plugins.PluginManager;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.statusbar.CommandQueue;
@@ -99,7 +101,6 @@
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.PulseExpansionHandler;
@@ -110,7 +111,6 @@
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -118,12 +118,10 @@
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
+import com.android.systemui.statusbar.notification.collection.init.NewNotifPipeline;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
-import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -134,6 +132,7 @@
 import com.android.systemui.statusbar.policy.RemoteInputUriController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.VolumeComponent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -174,7 +173,6 @@
     @Mock private ArrayList<NotificationEntry> mNotificationList;
     @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
     @Mock private BiometricUnlockController mBiometricUnlockController;
-    @Mock private NotificationData mNotificationData;
     @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
     @Mock private VisualStabilityManager mVisualStabilityManager;
     @Mock private NotificationListener mNotificationListener;
@@ -220,7 +218,6 @@
     @Mock private NotificationIconAreaController mNotificationIconAreaController;
     @Mock private StatusBarWindowViewController.Builder mStatusBarWindowViewControllerBuilder;
     @Mock private StatusBarWindowViewController mStatusBarWindowViewController;
-    @Mock private NotifLog mNotifLog;
     @Mock private DozeParameters mDozeParameters;
     @Mock private Lazy<LockscreenWallpaper> mLockscreenWallpaperLazy;
     @Mock private LockscreenWallpaper mLockscreenWallpaper;
@@ -228,13 +225,17 @@
     @Mock private LinearLayout mLockIconContainer;
     @Mock private ViewMediatorCallback mKeyguardVieMediatorCallback;
     @Mock private KeyguardLiftController mKeyguardLiftController;
+    @Mock private VolumeComponent mVolumeComponent;
     @Mock private CommandQueue mCommandQueue;
+    @Mock private Recents mRecents;
     @Mock private PluginManager mPluginManager;
     @Mock private Divider mDivider;
     @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
     @Mock private LightsOutNotifController mLightsOutNotifController;
     @Mock private ViewMediatorCallback mViewMediatorCallback;
     @Mock private DismissCallbackRegistry mDismissCallbackRegistry;
+    @Mock private ScreenPinningRequest mScreenPinningRequest;
+    @Mock private NotificationEntryManager mEntryManager;
 
     @Before
     public void setup() throws Exception {
@@ -255,10 +256,8 @@
         mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
 
         mMetricsLogger = new FakeMetricsLogger();
-        TestableNotificationEntryManager entryManager = new TestableNotificationEntryManager(
-                mNotificationData);
         NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
-                Dependency.get(UiOffloadThread.class), entryManager, mStatusBarStateController,
+                Dependency.get(UiOffloadThread.class), mEntryManager, mStatusBarStateController,
                 mExpansionStateLogger);
         notificationLogger.setVisibilityReporter(mock(Runnable.class));
 
@@ -327,7 +326,7 @@
                 ),
                 mNotificationGutsManager,
                 notificationLogger,
-                entryManager,
+                mEntryManager,
                 mNotificationInterruptionStateProvider,
                 mNotificationViewHierarchyManager,
                 mKeyguardViewMediator,
@@ -352,7 +351,7 @@
                 mVisualStabilityManager,
                 mDeviceProvisionedController,
                 mNavigationBarController,
-                mAssistManager,
+                () -> mAssistManager,
                 mNotificationListener,
                 configurationController,
                 mStatusBarWindowController,
@@ -363,9 +362,11 @@
                 mLockscreenWallpaperLazy,
                 mBiometricUnlockControllerLazy,
                 mDozeServiceHost,
-                mPowerManager,
+                mPowerManager, mScreenPinningRequest,
                 mDozeScrimController,
+                mVolumeComponent,
                 mCommandQueue,
+                Optional.of(mRecents),
                 mPluginManager,
                 mRemoteInputUriController,
                 Optional.of(mDivider),
@@ -388,7 +389,6 @@
 
         // TODO: we should be able to call mStatusBar.start() and have all the below values
         // initialized automatically.
-        mStatusBar.mComponents = mContext.getComponents();
         mStatusBar.mStatusBarWindow = mStatusBarWindowView;
         mStatusBar.mNotificationPanel = mNotificationPanelView;
         mStatusBar.mDozeScrimController = mDozeScrimController;
@@ -400,9 +400,6 @@
         mStatusBar.mStatusBarWindowViewController = mStatusBarWindowViewController;
         mStatusBar.startKeyguard();
         Dependency.get(InitController.class).executePostInitTasks();
-        entryManager.setUpForTest(mock(NotificationPresenter.class), mStackScroller,
-                mHeadsUpManager);
-        entryManager.addNotificationEntryListener(mEntryListener);
         notificationLogger.setUpWithContainer(mStackScroller);
     }
 
@@ -638,8 +635,7 @@
     public void testPanelOpenForHeadsUp() {
         when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
-        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
-        when(mNotificationList.size()).thenReturn(5);
+        when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
         when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true);
         mStatusBar.setBarStateForTest(StatusBarState.SHADE);
 
@@ -657,8 +653,8 @@
     @Test
     public void testPanelOpenAndClear() {
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
-        when(mNotificationList.size()).thenReturn(5);
+        when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
+
         when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
         mStatusBar.setBarStateForTest(StatusBarState.SHADE);
 
@@ -676,8 +672,7 @@
     @Test
     public void testPanelOpenAndNoClear() {
         when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
-        when(mNotificationData.getActiveNotifications()).thenReturn(mNotificationList);
-        when(mNotificationList.size()).thenReturn(5);
+        when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
         when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
         mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
 
@@ -835,19 +830,6 @@
                 any(UserHandle.class));
     }
 
-    public static class TestableNotificationEntryManager extends NotificationEntryManager {
-
-        public TestableNotificationEntryManager(NotificationData notificationData) {
-            super(notificationData, mock(NotifLog.class));
-        }
-
-        public void setUpForTest(NotificationPresenter presenter,
-                NotificationListContainer listContainer,
-                HeadsUpManagerPhone headsUpManager) {
-            super.setUpWithPresenter(presenter, listContainer, headsUpManager);
-        }
-    }
-
     public static class TestableNotificationInterruptionStateProvider extends
             NotificationInterruptionStateProvider {
 
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..e08551a 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,17 +75,18 @@
     @Mock private DozeLog mDozeLog;
     @Mock private DozeParameters mDozeParameters;
     @Mock private SuperStatusBarViewFactory mSuperStatusBarViewFactory;
+    @Mock private DockManager mDockManager;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
         mView = new StatusBarWindowView(getContext(), null);
-        mContext.putComponent(StatusBar.class, mStatusBar);
         when(mStatusBar.isDozing()).thenReturn(false);
         mDependency.injectTestDependency(ShadeController.class, mShadeController);
 
         when(mSuperStatusBarViewFactory.getStatusBarWindowView()).thenReturn(mView);
+        when(mDockManager.isDocked()).thenReturn(false);
 
         mController = new StatusBarWindowViewController.Builder(
                 new InjectionInflationController(
@@ -103,7 +105,8 @@
                 mDozeLog,
                 mDozeParameters,
                 new CommandQueue(mContext),
-                mSuperStatusBarViewFactory)
+                mSuperStatusBarViewFactory,
+                mDockManager)
                 .setShadeController(mShadeController)
                 .build();
         mController.setService(mStatusBar);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
index 4ccf8a4..0d1e1bd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HotspotControllerImplTest.java
@@ -43,6 +43,7 @@
 import org.mockito.invocation.InvocationOnMock;
 
 import java.util.ArrayList;
+import java.util.concurrent.Executor;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -73,7 +74,7 @@
                     .onConnectedClientsChanged(new ArrayList<>());
             return null;
         }).when(mWifiManager).registerSoftApCallback(any(WifiManager.SoftApCallback.class),
-                any(Handler.class));
+                any(Executor.class));
 
         mController = new HotspotControllerImpl(mContext, new Handler(mLooper.getLooper()));
         mController.handleSetListening(true);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
index 0bc7868a..e15ca1d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/FakeSensorManager.java
@@ -64,7 +64,8 @@
                 .getDefaultSensor(Sensor.TYPE_PROXIMITY);
         if (proxSensor == null) {
             // No prox? Let's create a fake one!
-            proxSensor = createSensor(Sensor.TYPE_PROXIMITY, null);
+            proxSensor =
+                    createSensor(Sensor.TYPE_PROXIMITY, null, 1 /* SENSOR_FLAG_WAKE_UP_SENSOR */);
         }
 
         mSensors = new FakeGenericSensor[]{
@@ -92,18 +93,6 @@
         if (s != null) {
             return s;
         }
-        switch(type) {
-            case Sensor.TYPE_PROXIMITY:
-                try {
-                    return createSensor(Sensor.TYPE_PROXIMITY, null);
-                } catch (Exception e) {
-                    // fall through
-                }
-                break;
-            default:
-                break;
-
-        }
         // Our mock sensors aren't wakeup, and it's a pain to create them that way. Instead, just
         // return non-wakeup sensors if we can't find a wakeup sensor.
         return getDefaultSensor(type, false /* wakeup */);
@@ -208,6 +197,10 @@
     }
 
     private Sensor createSensor(int type, @Nullable String stringType) throws Exception {
+        return createSensor(type, stringType, 0 /* flags */);
+    }
+
+    private Sensor createSensor(int type, @Nullable String stringType, int flags) throws Exception {
         Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
         constr.setAccessible(true);
         Sensor sensor = constr.newInstance();
@@ -225,7 +218,7 @@
         setSensorField(sensor, "mPower", 1);
         setSensorField(sensor, "mMinDelay", 1000);
         setSensorField(sensor, "mMaxDelay", 1000000000);
-        setSensorField(sensor, "mFlags", 0);
+        setSensorField(sensor, "mFlags", flags);
         setSensorField(sensor, "mId", -1);
 
         return sensor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
new file mode 100644
index 0000000..7b5417c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/time/FakeSystemClock.java
@@ -0,0 +1,111 @@
+/*
+ * 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.util.time;
+
+public class FakeSystemClock implements SystemClock {
+    private boolean mAutoIncrement = true;
+
+    private long mUptimeMillis;
+    private long mElapsedRealtime;
+    private long mElapsedRealtimeNanos;
+    private long mCurrentThreadTimeMillis;
+    private long mCurrentThreadTimeMicro;
+    private long mCurrentTimeMicro;
+
+    @Override
+    public long uptimeMillis() {
+        long value = mUptimeMillis;
+        if (mAutoIncrement) {
+            mUptimeMillis++;
+        }
+        return value;
+    }
+
+    @Override
+    public long elapsedRealtime() {
+        long value = mElapsedRealtime;
+        if (mAutoIncrement) {
+            mElapsedRealtime++;
+        }
+        return value;
+    }
+
+    @Override
+    public long elapsedRealtimeNanos() {
+        long value = mElapsedRealtimeNanos;
+        if (mAutoIncrement) {
+            mElapsedRealtimeNanos++;
+        }
+        return value;
+    }
+
+    @Override
+    public long currentThreadTimeMillis() {
+        long value = mCurrentThreadTimeMillis;
+        if (mAutoIncrement) {
+            mCurrentThreadTimeMillis++;
+        }
+        return value;
+    }
+
+    @Override
+    public long currentThreadTimeMicro() {
+        long value = mCurrentThreadTimeMicro;
+        if (mAutoIncrement) {
+            mCurrentThreadTimeMicro++;
+        }
+        return value;
+    }
+
+    @Override
+    public long currentTimeMicro() {
+        long value = mCurrentTimeMicro;
+        if (mAutoIncrement) {
+            mCurrentTimeMicro++;
+        }
+        return value;
+    }
+
+    public void setUptimeMillis(long uptimeMillis) {
+        mUptimeMillis = uptimeMillis;
+    }
+
+    public void setElapsedRealtime(long elapsedRealtime) {
+        mElapsedRealtime = elapsedRealtime;
+    }
+
+    public void setElapsedRealtimeNanos(long elapsedRealtimeNanos) {
+        mElapsedRealtimeNanos = elapsedRealtimeNanos;
+    }
+
+    public void setCurrentThreadTimeMillis(long currentThreadTimeMillis) {
+        mCurrentThreadTimeMillis = currentThreadTimeMillis;
+    }
+
+    public void setCurrentThreadTimeMicro(long currentThreadTimeMicro) {
+        mCurrentThreadTimeMicro = currentThreadTimeMicro;
+    }
+
+    public void setCurrentTimeMicro(long currentTimeMicro) {
+        mCurrentTimeMicro = currentTimeMicro;
+    }
+
+    /** If true, each call to get____ will be one higher than the previous call to that method. */
+    public void setAutoIncrement(boolean autoIncrement) {
+        mAutoIncrement = autoIncrement;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
index 2e945f2..2854665 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -44,6 +44,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.Optional;
+
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 public class VolumeDialogControllerImplTest extends SysuiTestCase {
@@ -67,8 +69,7 @@
 
     @Test
     public void testRegisteredWithDispatcher() {
-        verify(mBroadcastDispatcher).registerReceiver(
-                any(BroadcastReceiver.class),
+        verify(mBroadcastDispatcher).registerReceiver(any(BroadcastReceiver.class),
                 any(IntentFilter.class),
                 any(Handler.class)); // VolumeDialogControllerImpl does not call with user
     }
@@ -95,7 +96,8 @@
         when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE);
         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
         when(mStatusBar.isDeviceInteractive()).thenReturn(false);
-        when(mStatusBar.getWakefulnessState()).thenReturn(WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
+        when(mStatusBar.getWakefulnessState()).thenReturn(
+                WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP);
         mVolumeController.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
         verify(mCallback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
     }
@@ -103,8 +105,10 @@
     @Test
     public void testVolumeChangeW_nullStatusBar() {
         VolumeDialogControllerImpl.C callback = mock(VolumeDialogControllerImpl.C.class);
-        TestableVolumeDialogControllerImpl nullStatusBarTestableDialog =  new
-                TestableVolumeDialogControllerImpl(mContext, callback, null, mBroadcastDispatcher);
+        TestableVolumeDialogControllerImpl
+                nullStatusBarTestableDialog =
+                new TestableVolumeDialogControllerImpl(
+                        mContext, callback, null, mBroadcastDispatcher);
         nullStatusBarTestableDialog.setEnableDialogs(true, true);
         nullStatusBarTestableDialog.onVolumeChangedW(0, AudioManager.FLAG_SHOW_UI);
         verify(callback, times(1)).onShowRequested(Events.SHOW_REASON_VOLUME_CHANGED);
@@ -125,9 +129,10 @@
     static class TestableVolumeDialogControllerImpl extends VolumeDialogControllerImpl {
         TestableVolumeDialogControllerImpl(Context context, C callback, StatusBar s,
                 BroadcastDispatcher broadcastDispatcher) {
-            super(context, broadcastDispatcher);
+            super(
+                    context, broadcastDispatcher,
+                    s == null ? Optional.empty() : Optional.of(() -> s));
             mCallbacks = callback;
-            mStatusBar = s;
         }
     }
 
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/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 6f43529..7fdd83b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -98,6 +98,7 @@
 import com.android.internal.util.IntPair;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -179,6 +180,8 @@
 
     private final AccessibilityDisplayListener mA11yDisplayListener;
 
+    private final ActivityTaskManagerInternal mActivityTaskManagerService;
+
     private final MainHandler mMainHandler;
 
     private final SystemActionPerformer mSystemActionPerformer;
@@ -260,6 +263,7 @@
                 mWindowManagerService, this, mSecurityPolicy, this);
         mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
         mSecurityPolicy.setAccessibilityWindowManager(mA11yWindowManager);
+        mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
 
         registerBroadcastReceivers();
         new AccessibilityContentObserver(mMainHandler).register(
@@ -1435,7 +1439,7 @@
                     service = new AccessibilityServiceConnection(userState, mContext, componentName,
                             installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
                             this, mWindowManagerService, mSystemActionPerformer,
-                            mA11yWindowManager);
+                            mA11yWindowManager, mActivityTaskManagerService);
                 } else if (userState.mBoundServices.contains(service)) {
                     continue;
                 }
@@ -2411,7 +2415,7 @@
                     userState, mContext,
                     COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
                     AccessibilityManagerService.this, mWindowManagerService,
-                    mSystemActionPerformer, mA11yWindowManager) {
+                    mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService) {
                 @Override
                 public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
                     return true;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
index a0a755a..6cadb6d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityServiceConnection.java
@@ -35,6 +35,7 @@
 import android.util.Slog;
 import android.view.Display;
 
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 import java.lang.ref.WeakReference;
@@ -59,6 +60,7 @@
     */
     final WeakReference<AccessibilityUserState> mUserStateWeakReference;
     final Intent mIntent;
+    final ActivityTaskManagerInternal mActivityTaskManagerService;
 
     private final Handler mMainHandler;
 
@@ -67,7 +69,8 @@
             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
             WindowManagerInternal windowManagerInternal,
-            SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm) {
+            SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager awm,
+            ActivityTaskManagerInternal activityTaskManagerService) {
         super(context, componentName, accessibilityServiceInfo, id, mainHandler, lock,
                 securityPolicy, systemSupport, windowManagerInternal, systemActionPerfomer, awm);
         mUserStateWeakReference = new WeakReference<AccessibilityUserState>(userState);
@@ -75,6 +78,7 @@
         mMainHandler = mainHandler;
         mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
                 com.android.internal.R.string.accessibility_binding_label);
+        mActivityTaskManagerService = activityTaskManagerService;
         final long identity = Binder.clearCallingIdentity();
         try {
             mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, mSystemSupport.getPendingIntentActivity(
@@ -101,6 +105,9 @@
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
+        mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(),
+                mAccessibilityServiceInfo.getResolveInfo().serviceInfo.applicationInfo.uid,
+                userState.mUserId);
     }
 
     public void unbindLocked() {
@@ -109,6 +116,8 @@
         if (userState == null) return;
         userState.removeServiceLocked(this);
         mSystemSupport.getMagnificationController().resetAllIfNeeded(mId);
+        mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
+                userState.mUserId);
         resetLocked();
     }
 
@@ -207,6 +216,11 @@
     @Override
     public void onServiceDisconnected(ComponentName componentName) {
         binderDied();
+        AccessibilityUserState userState = mUserStateWeakReference.get();
+        if (userState != null) {
+            mActivityTaskManagerService.setAllowAppSwitches(mComponentName.flattenToString(), -1,
+                    userState.mUserId);
+        }
     }
 
     @Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 770de09..c6bc106 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -91,6 +91,7 @@
         "android.hardware.light-V2.0-java",
         "android.hardware.power-V1.0-java",
         "android.hardware.tv.cec-V1.0-java",
+        "app-compat-annotations",
     ],
 
     required: [
diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java
index 190e6cf..7b02b6e 100644
--- a/services/core/java/com/android/server/DynamicSystemService.java
+++ b/services/core/java/com/android/server/DynamicSystemService.java
@@ -18,7 +18,6 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
-import android.gsi.GsiInstallParams;
 import android.gsi.GsiProgress;
 import android.gsi.IGsiService;
 import android.gsi.IGsid;
@@ -47,6 +46,7 @@
     private static final int GSID_ROUGH_TIMEOUT_MS = 8192;
     private static final String PATH_DEFAULT = "/data/gsi";
     private Context mContext;
+    private String mInstallPath;
     private volatile IGsiService mGsiService;
 
     DynamicSystemService(Context context) {
@@ -115,8 +115,8 @@
     }
 
     @Override
-    public boolean startInstallation(String name, long size, boolean readOnly)
-            throws RemoteException {
+    public boolean startInstallation() throws RemoteException {
+        IGsiService service = getGsiService();
         // priority from high to low: sysprop -> sdcard -> /data
         String path = SystemProperties.get("os.aot.path");
         if (path.isEmpty()) {
@@ -138,14 +138,19 @@
             }
             Slog.i(TAG, "startInstallation -> " + path);
         }
+        mInstallPath = path;
+        if (service.openInstall(path) != 0) {
+            Slog.i(TAG, "Failed to open " + path);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean createPartition(String name, long size, boolean readOnly)
+            throws RemoteException {
         IGsiService service = getGsiService();
-        GsiInstallParams installParams = new GsiInstallParams();
-        installParams.installDir = path;
-        installParams.name = name;
-        installParams.size = size;
-        installParams.wipe = readOnly;
-        installParams.readOnly = readOnly;
-        if (service.beginGsiInstall(installParams) != 0) {
+        if (service.createPartition(name, size, readOnly) != 0) {
             Slog.i(TAG, "Failed to install " + name);
             return false;
         }
@@ -153,6 +158,16 @@
     }
 
     @Override
+    public boolean finishInstallation() throws RemoteException {
+        IGsiService service = getGsiService();
+        if (service.closeInstall() != 0) {
+            Slog.i(TAG, "Failed to finish installation");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
     public GsiProgress getInstallationProgress() throws RemoteException {
         return getGsiService().getInstallProgress();
     }
@@ -190,6 +205,8 @@
 
     @Override
     public boolean remove() throws RemoteException {
+        IGsiService gsiService = getGsiService();
+        String install_dir = gsiService.getInstalledGsiImageDir();
         return getGsiService().removeGsi();
     }
 
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/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 447ed59..f8b0072 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,6 +16,10 @@
 
 package com.android.server;
 
+import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED;
+
+import static java.util.Arrays.copyOf;
+
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.content.BroadcastReceiver;
@@ -286,7 +290,7 @@
             switch (msg.what) {
                 case MSG_USER_SWITCHED: {
                     if (VDBG) log("MSG_USER_SWITCHED userId=" + msg.arg1);
-                    int numPhones = TelephonyManager.getDefault().getPhoneCount();
+                    int numPhones = getTelephonyManager().getPhoneCount();
                     for (int sub = 0; sub < numPhones; sub++) {
                         TelephonyRegistry.this.notifyCellLocationForSubscriber(sub,
                                 mCellLocation[sub]);
@@ -367,10 +371,111 @@
                     mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB,
                             newDefaultPhoneId, newDefaultSubId));
                 }
+            } else if (action.equals(ACTION_MULTI_SIM_CONFIG_CHANGED)) {
+                onMultiSimConfigChanged();
             }
         }
     };
 
+    private TelephonyManager getTelephonyManager() {
+        return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+    }
+
+    private void onMultiSimConfigChanged() {
+        int oldNumPhones = mNumPhones;
+        mNumPhones = getTelephonyManager().getActiveModemCount();
+        if (oldNumPhones == mNumPhones) return;
+
+        if (DBG) {
+            log("TelephonyRegistry: activeModemCount changed from " + oldNumPhones
+                    + " to " + mNumPhones);
+        }
+        mCallState = copyOf(mCallState, mNumPhones);
+        mDataActivity = copyOf(mCallState, mNumPhones);
+        mDataConnectionState = copyOf(mCallState, mNumPhones);
+        mDataConnectionNetworkType = copyOf(mCallState, mNumPhones);
+        mCallIncomingNumber = copyOf(mCallIncomingNumber, mNumPhones);
+        mServiceState = copyOf(mServiceState, mNumPhones);
+        mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones);
+        mDataActivationState = copyOf(mDataActivationState, mNumPhones);
+        mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones);
+        mSignalStrength = copyOf(mSignalStrength, mNumPhones);
+        mMessageWaiting = copyOf(mMessageWaiting, mNumPhones);
+        mCallForwarding = copyOf(mCallForwarding, mNumPhones);
+        mCellLocation = copyOf(mCellLocation, mNumPhones);
+        mSrvccState = copyOf(mSrvccState, mNumPhones);
+        mOtaspMode = copyOf(mOtaspMode, mNumPhones);
+        mPreciseCallState = copyOf(mPreciseCallState, mNumPhones);
+        mForegroundCallState = copyOf(mForegroundCallState, mNumPhones);
+        mBackgroundCallState = copyOf(mBackgroundCallState, mNumPhones);
+        mRingingCallState = copyOf(mRingingCallState, mNumPhones);
+        mCallDisconnectCause = copyOf(mCallDisconnectCause, mNumPhones);
+        mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
+        mCallQuality = copyOf(mCallQuality, mNumPhones);
+        mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
+        mCallAttributes = copyOf(mCallAttributes, mNumPhones);
+        mPreciseDataConnectionState = copyOf(mPreciseDataConnectionState, mNumPhones);
+        mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
+        mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
+
+        // ds -> ss switch.
+        if (mNumPhones < oldNumPhones) {
+            cutListToSize(mCellInfo, mNumPhones);
+            cutListToSize(mImsReasonInfo, mNumPhones);
+            cutListToSize(mPhysicalChannelConfigs, mNumPhones);
+            return;
+        }
+
+        // mNumPhones > oldNumPhones: ss -> ds switch
+        for (int i = oldNumPhones; i < mNumPhones; i++) {
+            mCallState[i] =  TelephonyManager.CALL_STATE_IDLE;
+            mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
+            mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+            mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+            mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+            mCallIncomingNumber[i] =  "";
+            mServiceState[i] =  new ServiceState();
+            mSignalStrength[i] =  new SignalStrength();
+            mUserMobileDataState[i] = false;
+            mMessageWaiting[i] =  false;
+            mCallForwarding[i] =  false;
+            mCellLocation[i] = new Bundle();
+            mCellInfo.add(i, null);
+            mImsReasonInfo.add(i, null);
+            mSrvccState[i] = TelephonyManager.SRVCC_STATE_HANDOVER_NONE;
+            mPhysicalChannelConfigs.add(i, new ArrayList<>());
+            mOtaspMode[i] = TelephonyManager.OTASP_UNKNOWN;
+            mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
+            mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
+            mCallQuality[i] = new CallQuality();
+            mCallAttributes[i] = new CallAttributes(new PreciseCallState(),
+                    TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+            mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+            mPreciseCallState[i] = new PreciseCallState();
+            mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+            mForegroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+            mBackgroundCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+            mPreciseDataConnectionState[i] = new PreciseDataConnectionState();
+        }
+
+        // Note that location can be null for non-phone builds like
+        // like the generic one.
+        CellLocation  location = CellLocation.getEmpty();
+        if (location != null) {
+            for (int i = oldNumPhones; i < mNumPhones; i++) {
+                location.fillInNotifierBundle(mCellLocation[i]);
+            }
+        }
+    }
+
+    private void cutListToSize(List list, int size) {
+        if (list == null) return;
+
+        while (list.size() > size) {
+            list.remove(list.size() - 1);
+        }
+    }
+
     // we keep a copy of all of the state so we can send it out when folks
     // register for it
     //
@@ -385,7 +490,7 @@
         mContext = context;
         mBatteryStats = BatteryStatsService.getService();
 
-        int numPhones = TelephonyManager.getDefault().getSupportedModemCount();
+        int numPhones = getTelephonyManager().getActiveModemCount();
         if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones);
         mNumPhones = numPhones;
         mCallState = new int[numPhones];
@@ -467,6 +572,7 @@
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
+        filter.addAction(ACTION_MULTI_SIM_CONFIG_CHANGED);
         log("systemRunning register for intents");
         mContext.registerReceiver(mBroadcastReceiver, filter);
     }
@@ -2014,7 +2120,7 @@
             final int recordCount = mRecords.size();
             pw.println("last known state:");
             pw.increaseIndent();
-            for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+            for (int i = 0; i < getTelephonyManager().getPhoneCount(); i++) {
                 pw.println("Phone Id=" + i);
                 pw.increaseIndent();
                 pw.println("mCallState=" + mCallState[i]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a6d216f..4bb29f0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24,6 +24,7 @@
 import static android.Manifest.permission.REMOVE_TASKS;
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
 import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL;
 import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
@@ -3054,7 +3055,7 @@
      * @param userId
      * @param event
      * @param appToken ActivityRecord's appToken.
-     * @param taskRoot TaskRecord's root
+     * @param taskRoot Task's root
      */
     public void updateActivityUsageStats(ComponentName activity, int userId, int event,
             IBinder appToken, ComponentName taskRoot) {
@@ -16060,13 +16061,12 @@
 
             boolean disableHiddenApiChecks = ai.usesNonSdkApi()
                     || (flags & INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS) != 0;
-            if (disableHiddenApiChecks) {
+            boolean disableTestApiChecks = disableHiddenApiChecks
+                    || (flags & INSTR_FLAG_DISABLE_TEST_API_CHECKS) != 0;
+            if (disableHiddenApiChecks || disableTestApiChecks) {
                 enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS,
                         "disable hidden API checks");
             }
-            // Allow instrumented processes access to test APIs.
-            // TODO(satayev): make this configurable via testing framework.
-            boolean disableTestApiChecks = true;
 
             final boolean mountExtStorageFull = isCallerShell()
                     && (flags & INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL) != 0;
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59acdcf..1f56176 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -3028,7 +3028,8 @@
             pw.println("      --allow-background-activity-starts: The receiver may start activities");
             pw.println("          even if in the background.");
             pw.println("  instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]");
-            pw.println("          [--user <USER_ID> | current] [--no-hidden-api-checks]");
+            pw.println("          [--user <USER_ID> | current]");
+            pw.println("          [--no-hidden-api-checks [--no-test-api-checks]]");
             pw.println("          [--no-isolated-storage]");
             pw.println("          [--no-window-animation] [--abi <ABI>] <COMPONENT>");
             pw.println("      Start an Instrumentation.  Typically this target <COMPONENT> is in the");
@@ -3048,6 +3049,8 @@
             pw.println("      --user <USER_ID> | current: Specify user instrumentation runs in;");
             pw.println("          current user if not specified.");
             pw.println("      --no-hidden-api-checks: disable restrictions on use of hidden API.");
+            pw.println("      --no-test-api-checks: disable restrictions to test APIs, if hidden");
+            pw.println("          API checks are enabled.");
             pw.println("      --no-isolated-storage: don't use isolated storage sandbox and ");
             pw.println("          mount full external storage");
             pw.println("      --no-window-animation: turn off window animations while running.");
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 6355af6..9a92778 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -61,6 +61,7 @@
 import android.hardware.hdmi.HdmiTvClient;
 import android.hardware.input.InputManager;
 import android.hardware.usb.UsbManager;
+import android.hidl.manager.V1_0.IServiceManager;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioFocusRequest;
@@ -148,10 +149,12 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -722,6 +725,8 @@
 
         AudioSystem.setErrorCallback(mAudioSystemCallback);
 
+        updateAudioHalPids();
+
         boolean cameraSoundForced = readCameraSoundForced();
         mCameraSoundForced = new Boolean(cameraSoundForced);
         sendMsg(mAudioHandler,
@@ -767,6 +772,8 @@
 
         readAndSetLowRamDevice();
 
+        mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
+
         // Call setRingerModeInt() to apply correct mute
         // state on streams affected by ringer mode.
         mRingerAndZenModeMutedStreams = 0;
@@ -950,6 +957,8 @@
         }
         Log.e(TAG, "Audioserver started.");
 
+        updateAudioHalPids();
+
         // indicate to audio HAL that we start the reconfiguration phase after a media
         // server crash
         // Note that we only execute this when the media server
@@ -958,6 +967,8 @@
 
         readAndSetLowRamDevice();
 
+        mIsCallScreeningModeSupported = AudioSystem.isCallScreeningModeSupported();
+
         // Restore device connection states, BT state
         mDeviceBroker.onAudioServerDied();
 
@@ -1462,10 +1473,13 @@
         }
         if (!TextUtils.isEmpty(packageName)) {
             PackageManager pm = mContext.getPackageManager();
+            ActivityManager am =
+                          (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE);
+
             if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName)
                     == PackageManager.PERMISSION_GRANTED) {
                 try {
-                    assistantUid = pm.getPackageUid(packageName, 0);
+                    assistantUid = pm.getPackageUidAsUser(packageName, am.getCurrentUser());
                 } catch (PackageManager.NameNotFoundException e) {
                     Log.e(TAG,
                             "updateAssistantUId() could not find UID for package: " + packageName);
@@ -2783,10 +2797,6 @@
                 setSystemAudioMute(mute);
                 AudioSystem.setMasterMute(mute);
                 sendMasterMuteUpdate(mute, flags);
-
-                Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
-                intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
-                sendBroadcastToAll(intent);
             }
         }
     }
@@ -2905,11 +2915,14 @@
             final boolean currentMute = AudioSystem.isMicrophoneMuted();
             final long identity = Binder.clearCallingIdentity();
             AudioSystem.muteMicrophone(muted);
-            Binder.restoreCallingIdentity(identity);
-            if (muted != currentMute) {
-                mContext.sendBroadcastAsUser(
+            try {
+                if (muted != currentMute) {
+                    mContext.sendBroadcastAsUser(
                         new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
                                 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
             }
         }
     }
@@ -3280,6 +3293,12 @@
             return;
         }
 
+        if (mode == AudioSystem.MODE_CALL_SCREENING && !mIsCallScreeningModeSupported) {
+            Log.w(TAG, "setMode(MODE_CALL_SCREENING) not permitted "
+                    + "when call screening is not supported");
+            return;
+        }
+
         if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
             return;
         }
@@ -3410,6 +3429,14 @@
         return mMode;
     }
 
+    /** cached value read from audiopolicy manager after initialization. */
+    private boolean mIsCallScreeningModeSupported = false;
+
+    /** @see AudioManager#isCallScreeningModeSupported() */
+    public boolean isCallScreeningModeSupported() {
+        return mIsCallScreeningModeSupported;
+    }
+
     //==========================================================================================
     // Sound Effects
     //==========================================================================================
@@ -3910,8 +3937,7 @@
         final boolean muteSystem = (zenPolicy.priorityCategories
                 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0;
         final boolean muteNotificationAndRing = ZenModeConfig
-                .areAllPriorityOnlyRingerSoundsMuted(
-                        mNm.getConsolidatedNotificationPolicy());
+                .areAllPriorityOnlyRingerSoundsMuted(zenPolicy);
         return muteAlarms && isAlarm(streamType)
                 || muteMedia && isMedia(streamType)
                 || muteSystem && isSystem(streamType)
@@ -3924,11 +3950,12 @@
 
     /**
      * Notifications, ringer and system sounds are controlled by the ringer:
-     * {@link ZenModeHelper.RingerModeDelegate#getRingerModeAffectedStreams(int)}
+     * {@link ZenModeHelper.RingerModeDelegate#getRingerModeAffectedStreams(int)} but can
+     * also be muted by DND based on the DND mode:
      * DND total silence: media and alarms streams can be muted by DND
      * DND alarms only: no streams additionally controlled by DND
-     * DND priority only: alarms, media, system streams can be muted by DND based on
-     * zenPolicy (this method determines which streams)
+     * DND priority only: alarms, media, system, ringer and notification streams can be muted by
+     * DND.  The current applied zenPolicy determines which streams will be muted by DND.
      * @return true if changed, else false
      */
     private boolean updateZenModeAffectedStreams() {
@@ -3960,6 +3987,11 @@
                     & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0) {
                 zenModeAffectedStreams |= 1 << AudioManager.STREAM_SYSTEM;
             }
+
+            if (ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(zenPolicy)) {
+                zenModeAffectedStreams |= 1 << AudioManager.STREAM_NOTIFICATION;
+                zenModeAffectedStreams |= 1 << AudioManager.STREAM_RING;
+            }
         }
 
         if (mZenModeAffectedStreams != zenModeAffectedStreams) {
@@ -6137,6 +6169,7 @@
         pw.print("  mHdmiPlaybackClient="); pw.println(mHdmiPlaybackClient);
         pw.print("  mHdmiTvClient="); pw.println(mHdmiTvClient);
         pw.print("  mHdmiSystemAudioSupported="); pw.println(mHdmiSystemAudioSupported);
+        pw.print("  mIsCallScreeningModeSupported="); pw.println(mIsCallScreeningModeSupported);
 
         dumpAudioPolicies(pw);
         mDynPolicyLogger.dump(pw);
@@ -7296,6 +7329,41 @@
     }
 
     //======================
+    // Audio HAL process dump
+    //======================
+
+    private static final String AUDIO_HAL_SERVICE_PREFIX = "android.hardware.audio";
+
+    private Set<Integer> getAudioHalPids() {
+        try {
+            IServiceManager serviceManager = IServiceManager.getService();
+            ArrayList<IServiceManager.InstanceDebugInfo> dump =
+                    serviceManager.debugDump();
+            HashSet<Integer> pids = new HashSet<>();
+            for (IServiceManager.InstanceDebugInfo info : dump) {
+                if (info.pid != IServiceManager.PidConstant.NO_PID
+                        && info.interfaceName != null
+                        && info.interfaceName.startsWith(AUDIO_HAL_SERVICE_PREFIX)) {
+                    pids.add(info.pid);
+                }
+            }
+            return pids;
+        } catch (RemoteException e) {
+            return new HashSet<Integer>();
+        }
+    }
+
+    private void updateAudioHalPids() {
+        Set<Integer> pidsSet = getAudioHalPids();
+        if (pidsSet.isEmpty()) {
+            Slog.w(TAG, "Could not retrieve audio HAL service pids");
+            return;
+        }
+        int[] pidsArray = pidsSet.stream().mapToInt(Integer::intValue).toArray();
+        AudioSystem.setAudioHalPids(pidsArray);
+    }
+
+    //======================
     // misc
     //======================
     private final HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index bd129f7..41008c2 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -437,7 +437,8 @@
     }
 
     int dispatchFocusChange(int focusChange) {
-        if (mFocusDispatcher == null) {
+        final IAudioFocusDispatcher fd = mFocusDispatcher;
+        if (fd == null) {
             if (MediaFocusControl.DEBUG) { Log.e(TAG, "dispatchFocusChange: no focus dispatcher"); }
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
         }
@@ -457,7 +458,7 @@
             mFocusLossReceived = focusChange;
         }
         try {
-            mFocusDispatcher.dispatchAudioFocusChange(focusChange, mClientId);
+            fd.dispatchAudioFocusChange(focusChange, mClientId);
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "dispatchFocusChange: error talking to focus listener " + mClientId, e);
             return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
@@ -466,16 +467,18 @@
     }
 
     void dispatchFocusResultFromExtPolicy(int requestResult) {
-        if (mFocusDispatcher == null) {
+        final IAudioFocusDispatcher fd = mFocusDispatcher;
+        if (fd == null) {
             if (MediaFocusControl.DEBUG) {
                 Log.e(TAG, "dispatchFocusResultFromExtPolicy: no focus dispatcher");
             }
+            return;
         }
         if (DEBUG) {
             Log.v(TAG, "dispatching result" + requestResult + " to " + mClientId);
         }
         try {
-            mFocusDispatcher.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
+            fd.dispatchFocusResultFromExtPolicy(requestResult, mClientId);
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "dispatchFocusResultFromExtPolicy: error talking to focus listener"
                     + mClientId, e);
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 4a62bc5..bc7307b 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -394,6 +394,15 @@
      *     allowed.
      */
     @Override
+    public void notifyChange(Uri[] uris, IContentObserver observer,
+            boolean observerWantsSelfNotifications, int flags, int userHandle,
+            int targetSdkVersion, String callingPackage) {
+        for (Uri uri : uris) {
+            notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
+                    targetSdkVersion, callingPackage);
+        }
+    }
+
     public void notifyChange(Uri uri, IContentObserver observer,
             boolean observerWantsSelfNotifications, int flags, int userHandle,
             int targetSdkVersion, String callingPackage) {
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index ebaa5a1..dea47db 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -51,6 +51,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+import android.util.proto.ProtoInputStream;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
@@ -64,6 +66,9 @@
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Calendar;
@@ -428,7 +433,8 @@
     }
 
     // Primary list of all syncable authorities.  Also our global lock.
-    private final SparseArray<AuthorityInfo> mAuthorities =
+    @VisibleForTesting
+    final SparseArray<AuthorityInfo> mAuthorities =
             new SparseArray<AuthorityInfo>();
 
     private final HashMap<AccountAndUser, AccountInfo> mAccounts
@@ -437,7 +443,8 @@
     private final SparseArray<ArrayList<SyncInfo>> mCurrentSyncs
             = new SparseArray<ArrayList<SyncInfo>>();
 
-    private final SparseArray<SyncStatusInfo> mSyncStatus =
+    @VisibleForTesting
+    final SparseArray<SyncStatusInfo> mSyncStatus =
             new SparseArray<SyncStatusInfo>();
 
     private final ArrayList<SyncHistoryItem> mSyncHistory =
@@ -453,7 +460,8 @@
     private int mNextAuthorityId = 0;
 
     // We keep 4 weeks of stats.
-    private final DayStats[] mDayStats = new DayStats[7*4];
+    @VisibleForTesting
+    final DayStats[] mDayStats = new DayStats[7*4];
     private final Calendar mCal;
     private int mYear;
     private int mYearInDays;
@@ -464,6 +472,18 @@
 
     private int mSyncRandomOffset;
 
+    // STOPSHIP: b/143656271 this should be true on launch
+    private static final boolean DELETE_LEGACY_PARCEL_FILES = false;
+    private static final String LEGACY_STATUS_FILE_NAME = "status.bin";
+    private static final String LEGACY_STATISTICS_FILE_NAME = "stats.bin";
+
+    private static final String SYNC_DIR_NAME = "sync";
+    private static final String ACCOUNT_INFO_FILE_NAME = "accounts.xml";
+    private static final String STATUS_FILE_NAME = "status";
+    private static final String STATISTICS_FILE_NAME = "stats";
+
+    private File mSyncDir;
+
     /**
      * This file contains the core engine state: all accounts and the
      * settings for them.  It must never be lost, and should be changed
@@ -508,14 +528,15 @@
                 com.android.internal.R.bool.config_syncstorageengine_masterSyncAutomatically);
 
         File systemDir = new File(dataDir, "system");
-        File syncDir = new File(systemDir, "sync");
-        syncDir.mkdirs();
+        mSyncDir = new File(systemDir, SYNC_DIR_NAME);
+        mSyncDir.mkdirs();
 
-        maybeDeleteLegacyPendingInfoLocked(syncDir);
+        maybeDeleteLegacyPendingInfoLocked(mSyncDir);
 
-        mAccountInfoFile = new AtomicFile(new File(syncDir, "accounts.xml"), "sync-accounts");
-        mStatusFile = new AtomicFile(new File(syncDir, "status.bin"), "sync-status");
-        mStatisticsFile = new AtomicFile(new File(syncDir, "stats.bin"), "sync-stats");
+        mAccountInfoFile = new AtomicFile(new File(mSyncDir, ACCOUNT_INFO_FILE_NAME),
+                "sync-accounts");
+        mStatusFile = new AtomicFile(new File(mSyncDir, STATUS_FILE_NAME), "sync-status");
+        mStatisticsFile = new AtomicFile(new File(mSyncDir, STATISTICS_FILE_NAME), "sync-stats");
 
         readAccountInfoLocked();
         readStatusLocked();
@@ -2017,15 +2038,10 @@
     public static final int STATUS_FILE_END = 0;
     public static final int STATUS_FILE_ITEM = 100;
 
-    /**
-     * Read all sync status back in to the initial engine state.
-     */
-    private void readStatusLocked() {
-        if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
-            Slog.v(TAG_FILE, "Reading " + mStatusFile.getBaseFile());
-        }
+    private void readStatusParcelLocked(File parcel) {
         try {
-            byte[] data = mStatusFile.readFully();
+            final AtomicFile parcelFile = new AtomicFile(parcel);
+            byte[] data = parcelFile.readFully();
             Parcel in = Parcel.obtain();
             in.unmarshall(data, 0, data.length);
             in.setDataPosition(0);
@@ -2036,9 +2052,6 @@
                         SyncStatusInfo status = new SyncStatusInfo(in);
                         if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
                             status.pending = false;
-                            if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
-                                Slog.v(TAG_FILE, "Adding status for id " + status.authorityId);
-                            }
                             mSyncStatus.put(status.authorityId, status);
                         }
                     } catch (Exception e) {
@@ -2050,15 +2063,247 @@
                     break;
                 }
             }
-        } catch (java.io.IOException e) {
+        } catch (IOException e) {
             Slog.i(TAG, "No initial status");
         }
     }
 
+    private void upgradeStatusIfNeededLocked() {
+        final File parcelStatus = new File(mSyncDir, LEGACY_STATUS_FILE_NAME);
+        if (parcelStatus.exists() && !mStatusFile.exists()) {
+            readStatusParcelLocked(parcelStatus);
+            writeStatusLocked();
+        }
+
+        // if upgrade to proto was successful, delete parcel file
+        if (DELETE_LEGACY_PARCEL_FILES && mStatusFile.exists()) {
+            parcelStatus.delete();
+        }
+    }
+
+    /**
+     * Read all sync status back in to the initial engine state.
+     */
+    @VisibleForTesting
+    void readStatusLocked() {
+        upgradeStatusIfNeededLocked();
+
+        if (!mStatusFile.exists()) {
+            return;
+        }
+        try {
+            try (FileInputStream in = mStatusFile.openRead()) {
+                readStatusInfoLocked(in);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to read status info file.", e);
+        }
+    }
+
+    private void readStatusInfoLocked(InputStream in) throws IOException {
+        final ProtoInputStream proto = new ProtoInputStream(in);
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatusProto.STATUS:
+                    final long token = proto.start(SyncStatusProto.STATUS);
+                    final SyncStatusInfo status = readSyncStatusInfoLocked(proto);
+                    proto.end(token);
+                    if (mAuthorities.indexOfKey(status.authorityId) >= 0) {
+                        status.pending = false;
+                        mSyncStatus.put(status.authorityId, status);
+                    }
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return;
+            }
+        }
+    }
+
+    private SyncStatusInfo readSyncStatusInfoLocked(ProtoInputStream proto) throws IOException {
+        SyncStatusInfo status;
+        if (proto.nextField(SyncStatusProto.StatusInfo.AUTHORITY_ID)) {
+            //fast-path; this should work for most cases since the authority id is written first
+            status = new SyncStatusInfo(proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID));
+        } else {
+            // placeholder to read other data; assume the default authority id as 0
+            status = new SyncStatusInfo(0);
+        }
+
+        int successTimesCount = 0;
+        int failureTimesCount = 0;
+        ArrayList<Pair<Long, String>> lastEventInformation = new ArrayList<>();
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatusProto.StatusInfo.AUTHORITY_ID:
+                    // fast-path failed for some reason, rebuild the status from placeholder object
+                    Slog.w(TAG, "Failed to read the authority id via fast-path; "
+                            + "some data might not have been read.");
+                    status = new SyncStatusInfo(
+                            proto.readInt(SyncStatusProto.StatusInfo.AUTHORITY_ID), status);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME:
+                    status.lastSuccessTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE:
+                    status.lastSuccessSource = proto.readInt(
+                            SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_TIME:
+                    status.lastFailureTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.LAST_FAILURE_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE:
+                    status.lastFailureSource = proto.readInt(
+                            SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE:
+                    status.lastFailureMesg = proto.readString(
+                            SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME:
+                    status.initialFailureTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.PENDING:
+                    status.pending = proto.readBoolean(SyncStatusProto.StatusInfo.PENDING);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.INITIALIZE:
+                    status.initialize = proto.readBoolean(SyncStatusProto.StatusInfo.INITIALIZE);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES:
+                    status.addPeriodicSyncTime(
+                            proto.readLong(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES));
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_EVENT_INFO:
+                    final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
+                    final Pair<Long, String> lastEventInfo = parseLastEventInfoLocked(proto);
+                    if (lastEventInfo != null) {
+                        lastEventInformation.add(lastEventInfo);
+                    }
+                    proto.end(eventToken);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME:
+                    status.lastTodayResetTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.TOTAL_STATS:
+                    final long totalStatsToken = proto.start(
+                            SyncStatusProto.StatusInfo.TOTAL_STATS);
+                    readSyncStatusStatsLocked(proto, status.totalStats);
+                    proto.end(totalStatsToken);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.TODAY_STATS:
+                    final long todayStatsToken = proto.start(
+                            SyncStatusProto.StatusInfo.TODAY_STATS);
+                    readSyncStatusStatsLocked(proto, status.todayStats);
+                    proto.end(todayStatsToken);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.YESTERDAY_STATS:
+                    final long yesterdayStatsToken = proto.start(
+                            SyncStatusProto.StatusInfo.YESTERDAY_STATS);
+                    readSyncStatusStatsLocked(proto, status.yesterdayStats);
+                    proto.end(yesterdayStatsToken);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES:
+                    final long successTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES);
+                    if (successTimesCount == status.perSourceLastSuccessTimes.length) {
+                        Slog.w(TAG, "Attempted to read more per source last success times "
+                                + "than expected; data might be corrupted.");
+                        break;
+                    }
+                    status.perSourceLastSuccessTimes[successTimesCount] = successTime;
+                    successTimesCount++;
+                    break;
+                case (int) SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES:
+                    final long failureTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES);
+                    if (failureTimesCount == status.perSourceLastFailureTimes.length) {
+                        Slog.w(TAG, "Attempted to read more per source last failure times "
+                                + "than expected; data might be corrupted.");
+                        break;
+                    }
+                    status.perSourceLastFailureTimes[failureTimesCount] = failureTime;
+                    failureTimesCount++;
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    status.populateLastEventsInformation(lastEventInformation);
+                    return status;
+            }
+        }
+    }
+
+    private Pair<Long, String> parseLastEventInfoLocked(ProtoInputStream proto) throws IOException {
+        long time = 0;
+        String message = null;
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME:
+                    time = proto.readLong(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT:
+                    message = proto.readString(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return message == null ? null : new Pair<>(time, message);
+            }
+        }
+    }
+
+    private void readSyncStatusStatsLocked(ProtoInputStream proto, SyncStatusInfo.Stats stats)
+            throws IOException {
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME:
+                    stats.totalElapsedTime = proto.readLong(
+                            SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SYNCS:
+                    stats.numSyncs = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_FAILURES:
+                    stats.numFailures = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_FAILURES);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_CANCELS:
+                    stats.numCancels = proto.readInt(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER:
+                    stats.numSourceOther = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL:
+                    stats.numSourceLocal = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL:
+                    stats.numSourcePoll = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER:
+                    stats.numSourceUser = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC:
+                    stats.numSourcePeriodic = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC);
+                    break;
+                case (int) SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED:
+                    stats.numSourceFeed = proto.readInt(
+                            SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return;
+            }
+        }
+    }
+
     /**
      * Write all sync status to the sync status file.
      */
-    private void writeStatusLocked() {
+    @VisibleForTesting
+    void writeStatusLocked() {
         if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
             Slog.v(TAG_FILE, "Writing new " + mStatusFile.getBaseFile());
         }
@@ -2070,26 +2315,87 @@
         FileOutputStream fos = null;
         try {
             fos = mStatusFile.startWrite();
-            Parcel out = Parcel.obtain();
-            final int N = mSyncStatus.size();
-            for (int i=0; i<N; i++) {
-                SyncStatusInfo status = mSyncStatus.valueAt(i);
-                out.writeInt(STATUS_FILE_ITEM);
-                status.writeToParcel(out, 0);
-            }
-            out.writeInt(STATUS_FILE_END);
-            fos.write(out.marshall());
-            out.recycle();
-
+            writeStatusInfoLocked(fos);
             mStatusFile.finishWrite(fos);
-        } catch (java.io.IOException e1) {
-            Slog.w(TAG, "Error writing status", e1);
-            if (fos != null) {
-                mStatusFile.failWrite(fos);
-            }
+            fos = null;
+        } catch (IOException | IllegalArgumentException e) {
+            Slog.e(TAG, "Unable to write sync status to proto.", e);
+        } finally {
+            // when fos is null (successful write), this is a no-op.
+            mStatusFile.failWrite(fos);
         }
     }
 
+    private void writeStatusInfoLocked(OutputStream out) {
+        final ProtoOutputStream proto = new ProtoOutputStream(out);
+        final int size = mSyncStatus.size();
+        for (int i = 0; i < size; i++) {
+            final SyncStatusInfo info = mSyncStatus.valueAt(i);
+            final long token = proto.start(SyncStatusProto.STATUS);
+            // authority id should be written first to take advantage of the fast path in read
+            proto.write(SyncStatusProto.StatusInfo.AUTHORITY_ID, info.authorityId);
+            proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_TIME, info.lastSuccessTime);
+            proto.write(SyncStatusProto.StatusInfo.LAST_SUCCESS_SOURCE, info.lastSuccessSource);
+            proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_TIME, info.lastFailureTime);
+            proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_SOURCE, info.lastFailureSource);
+            proto.write(SyncStatusProto.StatusInfo.LAST_FAILURE_MESSAGE, info.lastFailureMesg);
+            proto.write(SyncStatusProto.StatusInfo.INITIAL_FAILURE_TIME, info.initialFailureTime);
+            proto.write(SyncStatusProto.StatusInfo.PENDING, info.pending);
+            proto.write(SyncStatusProto.StatusInfo.INITIALIZE, info.initialize);
+            final int periodicSyncTimesSize = info.getPeriodicSyncTimesSize();
+            for (int j = 0; j < periodicSyncTimesSize; j++) {
+                proto.write(SyncStatusProto.StatusInfo.PERIODIC_SYNC_TIMES,
+                        info.getPeriodicSyncTime(j));
+            }
+            final int lastEventsSize = info.getEventCount();
+            for (int j = 0; j < lastEventsSize; j++) {
+                final long eventToken = proto.start(SyncStatusProto.StatusInfo.LAST_EVENT_INFO);
+                proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT_TIME,
+                        info.getEventTime(j));
+                proto.write(SyncStatusProto.StatusInfo.LastEventInfo.LAST_EVENT, info.getEvent(j));
+                proto.end(eventToken);
+            }
+            proto.write(SyncStatusProto.StatusInfo.LAST_TODAY_RESET_TIME, info.lastTodayResetTime);
+
+            final long totalStatsToken = proto.start(SyncStatusProto.StatusInfo.TOTAL_STATS);
+            writeStatusStatsLocked(proto, info.totalStats);
+            proto.end(totalStatsToken);
+            final long todayStatsToken = proto.start(SyncStatusProto.StatusInfo.TODAY_STATS);
+            writeStatusStatsLocked(proto, info.todayStats);
+            proto.end(todayStatsToken);
+            final long yesterdayStatsToken = proto.start(
+                    SyncStatusProto.StatusInfo.YESTERDAY_STATS);
+            writeStatusStatsLocked(proto, info.yesterdayStats);
+            proto.end(yesterdayStatsToken);
+
+            final int lastSuccessTimesSize = info.perSourceLastSuccessTimes.length;
+            for (int j = 0; j < lastSuccessTimesSize; j++) {
+                proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_SUCCESS_TIMES,
+                        info.perSourceLastSuccessTimes[j]);
+            }
+            final int lastFailureTimesSize = info.perSourceLastFailureTimes.length;
+            for (int j = 0; j < lastFailureTimesSize; j++) {
+                proto.write(SyncStatusProto.StatusInfo.PER_SOURCE_LAST_FAILURE_TIMES,
+                        info.perSourceLastFailureTimes[j]);
+            }
+            proto.end(token);
+        }
+        proto.flush();
+    }
+
+    private void writeStatusStatsLocked(ProtoOutputStream proto, SyncStatusInfo.Stats stats) {
+        proto.write(SyncStatusProto.StatusInfo.Stats.TOTAL_ELAPSED_TIME, stats.totalElapsedTime);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SYNCS, stats.numSyncs);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_FAILURES, stats.numFailures);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_CANCELS, stats.numCancels);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_OTHER, stats.numSourceOther);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_LOCAL, stats.numSourceLocal);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_POLL, stats.numSourcePoll);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_USER, stats.numSourceUser);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_PERIODIC, stats.numSourcePeriodic);
+        proto.write(SyncStatusProto.StatusInfo.Stats.NUM_SOURCE_FEED, stats.numSourceFeed);
+    }
+
     private void requestSync(AuthorityInfo authorityInfo, int reason, Bundle extras,
             @SyncExemption int syncExemptionFlag, int callingUid, int callingPid) {
         if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
@@ -2126,20 +2432,17 @@
     public static final int STATISTICS_FILE_ITEM_OLD = 100;
     public static final int STATISTICS_FILE_ITEM = 101;
 
-    /**
-     * Read all sync statistics back in to the initial engine state.
-     */
-    private void readStatisticsLocked() {
+    private void readStatsParcelLocked(File parcel) {
         try {
-            byte[] data = mStatisticsFile.readFully();
+            final AtomicFile parcelFile = new AtomicFile(parcel);
+            byte[] data = parcelFile.readFully();
             Parcel in = Parcel.obtain();
             in.unmarshall(data, 0, data.length);
             in.setDataPosition(0);
             int token;
             int index = 0;
             while ((token=in.readInt()) != STATISTICS_FILE_END) {
-                if (token == STATISTICS_FILE_ITEM
-                        || token == STATISTICS_FILE_ITEM_OLD) {
+                if (token == STATISTICS_FILE_ITEM || token == STATISTICS_FILE_ITEM_OLD) {
                     int day = in.readInt();
                     if (token == STATISTICS_FILE_ITEM_OLD) {
                         day = day - 2009 + 14245;  // Magic!
@@ -2159,15 +2462,110 @@
                     break;
                 }
             }
-        } catch (java.io.IOException e) {
+        } catch (IOException e) {
             Slog.i(TAG, "No initial statistics");
         }
     }
 
+    private void upgradeStatisticsIfNeededLocked() {
+        final File parcelStats = new File(mSyncDir, LEGACY_STATISTICS_FILE_NAME);
+        if (parcelStats.exists() && !mStatisticsFile.exists()) {
+            readStatsParcelLocked(parcelStats);
+            writeStatisticsLocked();
+        }
+
+        // if upgrade to proto was successful, delete parcel file
+        if (DELETE_LEGACY_PARCEL_FILES && mStatisticsFile.exists()) {
+            parcelStats.delete();
+        }
+    }
+
+    /**
+     * Read all sync statistics back in to the initial engine state.
+     */
+    private void readStatisticsLocked() {
+        upgradeStatisticsIfNeededLocked();
+
+        if (!mStatisticsFile.exists()) {
+            return;
+        }
+        try {
+            try (FileInputStream in = mStatisticsFile.openRead()) {
+                readDayStatsLocked(in);
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "Unable to read day stats file.", e);
+        }
+    }
+
+    private void readDayStatsLocked(InputStream in) throws IOException {
+        final ProtoInputStream proto = new ProtoInputStream(in);
+        int statsCount = 0;
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatisticsProto.STATS:
+                    final long token = proto.start(SyncStatisticsProto.STATS);
+                    final DayStats stats = readIndividualDayStatsLocked(proto);
+                    proto.end(token);
+                    mDayStats[statsCount] = stats;
+                    statsCount++;
+                    if (statsCount == mDayStats.length) {
+                        return;
+                    }
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return;
+            }
+        }
+    }
+
+    private DayStats readIndividualDayStatsLocked(ProtoInputStream proto) throws IOException {
+        DayStats stats;
+        if (proto.nextField(SyncStatisticsProto.DayStats.DAY)) {
+            // fast-path; this should work for most cases since the day is written first
+            stats = new DayStats(proto.readInt(SyncStatisticsProto.DayStats.DAY));
+        } else {
+            // placeholder to read other data; assume the default day as 0
+            stats = new DayStats(0);
+        }
+
+        while (true) {
+            switch (proto.nextField()) {
+                case (int) SyncStatisticsProto.DayStats.DAY:
+                    // fast-path failed for some reason, rebuild stats from placeholder object
+                    Slog.w(TAG, "Failed to read the day via fast-path; some data "
+                            + "might not have been read.");
+                    final DayStats temp = new DayStats(
+                            proto.readInt(SyncStatisticsProto.DayStats.DAY));
+                    temp.successCount = stats.successCount;
+                    temp.successTime = stats.successTime;
+                    temp.failureCount = stats.failureCount;
+                    temp.failureTime = stats.failureTime;
+                    stats = temp;
+                    break;
+                case (int) SyncStatisticsProto.DayStats.SUCCESS_COUNT:
+                    stats.successCount = proto.readInt(SyncStatisticsProto.DayStats.SUCCESS_COUNT);
+                    break;
+                case (int) SyncStatisticsProto.DayStats.SUCCESS_TIME:
+                    stats.successTime = proto.readLong(SyncStatisticsProto.DayStats.SUCCESS_TIME);
+                    break;
+                case (int) SyncStatisticsProto.DayStats.FAILURE_COUNT:
+                    stats.failureCount = proto.readInt(SyncStatisticsProto.DayStats.FAILURE_COUNT);
+                    break;
+                case (int) SyncStatisticsProto.DayStats.FAILURE_TIME:
+                    stats.failureTime = proto.readLong(SyncStatisticsProto.DayStats.FAILURE_TIME);
+                    break;
+                case ProtoInputStream.NO_MORE_FIELDS:
+                    return stats;
+            }
+        }
+    }
+
     /**
      * Write all sync statistics to the sync status file.
      */
-    private void writeStatisticsLocked() {
+    @VisibleForTesting
+    void writeStatisticsLocked() {
         if (Log.isLoggable(TAG_FILE, Log.VERBOSE)) {
             Slog.v(TAG, "Writing new " + mStatisticsFile.getBaseFile());
         }
@@ -2179,33 +2577,38 @@
         FileOutputStream fos = null;
         try {
             fos = mStatisticsFile.startWrite();
-            Parcel out = Parcel.obtain();
-            final int N = mDayStats.length;
-            for (int i=0; i<N; i++) {
-                DayStats ds = mDayStats[i];
-                if (ds == null) {
-                    break;
-                }
-                out.writeInt(STATISTICS_FILE_ITEM);
-                out.writeInt(ds.day);
-                out.writeInt(ds.successCount);
-                out.writeLong(ds.successTime);
-                out.writeInt(ds.failureCount);
-                out.writeLong(ds.failureTime);
-            }
-            out.writeInt(STATISTICS_FILE_END);
-            fos.write(out.marshall());
-            out.recycle();
-
+            writeDayStatsLocked(fos);
             mStatisticsFile.finishWrite(fos);
-        } catch (java.io.IOException e1) {
-            Slog.w(TAG, "Error writing stats", e1);
-            if (fos != null) {
-                mStatisticsFile.failWrite(fos);
-            }
+            fos = null;
+        } catch (IOException | IllegalArgumentException e) {
+            Slog.e(TAG, "Unable to write day stats to proto.", e);
+        } finally {
+            // when fos is null (successful write), this is a no-op.
+            mStatisticsFile.failWrite(fos);
         }
     }
 
+    private void writeDayStatsLocked(OutputStream out)
+            throws IOException, IllegalArgumentException {
+        final ProtoOutputStream proto = new ProtoOutputStream(out);
+        final int size = mDayStats.length;
+        for (int i = 0; i < size; i++) {
+            final DayStats stats = mDayStats[i];
+            if (stats == null) {
+                break;
+            }
+            final long token = proto.start(SyncStatisticsProto.STATS);
+            // day should be written first to take advantage of the fast path in read
+            proto.write(SyncStatisticsProto.DayStats.DAY, stats.day);
+            proto.write(SyncStatisticsProto.DayStats.SUCCESS_COUNT, stats.successCount);
+            proto.write(SyncStatisticsProto.DayStats.SUCCESS_TIME, stats.successTime);
+            proto.write(SyncStatisticsProto.DayStats.FAILURE_COUNT, stats.failureCount);
+            proto.write(SyncStatisticsProto.DayStats.FAILURE_TIME, stats.failureTime);
+            proto.end(token);
+        }
+        proto.flush();
+    }
+
     /**
      * Let the BackupManager know that account sync settings have changed. This will trigger
      * {@link com.android.server.backup.SystemBackupAgent} to run.
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/engine/RuleEvaluationEngine.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
index e90612e..f0bb192 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluationEngine.java
@@ -16,8 +16,6 @@
 
 package com.android.server.integrity.engine;
 
-import android.util.Slog;
-
 import com.android.server.integrity.model.AppInstallMetadata;
 import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.integrity.model.Rule;
@@ -53,23 +51,11 @@
      *
      * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
      *                           against.
-     * @return A rule matching the metadata. If there are multiple matching rules, returns any. If
-     * no rules are matching, returns {@link Rule#EMPTY}.
+     * @return result of the integrity check
      */
     public IntegrityCheckResult evaluate(AppInstallMetadata appInstallMetadata) {
         List<Rule> rules = loadRules(appInstallMetadata);
-        Rule matchedRule = RuleEvaluator.evaluateRules(rules, appInstallMetadata);
-        if (matchedRule == Rule.EMPTY) {
-            return IntegrityCheckResult.allow();
-        } else {
-            switch (matchedRule.getEffect()) {
-                case DENY:
-                    return IntegrityCheckResult.deny(matchedRule);
-                default:
-                    Slog.e(TAG, "Matched a non-DENY rule: " + matchedRule);
-                    return IntegrityCheckResult.allow();
-            }
-        }
+        return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
     }
 
     private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
diff --git a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
index 6416505..7deae46 100644
--- a/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
+++ b/services/core/java/com/android/server/integrity/engine/RuleEvaluator.java
@@ -16,14 +16,20 @@
 
 package com.android.server.integrity.engine;
 
+import static com.android.server.integrity.model.Rule.DENY;
+import static com.android.server.integrity.model.Rule.FORCE_ALLOW;
+
+import android.annotation.NonNull;
 import android.util.Slog;
 
 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.IntegrityCheckResult;
 import com.android.server.integrity.model.OpenFormula;
 import com.android.server.integrity.model.Rule;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -40,67 +46,40 @@
      * <p>Rules must be in disjunctive normal form (DNF). A rule should contain AND'ed formulas
      * only. All rules are OR'ed together by default.
      *
-     * @param rules              The list of rules to evaluate.
+     * @param rules The list of rules to evaluate.
      * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
-     *                           against.
-     * @return A rule matching the metadata. If there are multiple matching rules, returns any. If
-     * no rules are matching, returns {@link Rule#EMPTY}.
+     *     against.
+     * @return result of the integrity check
      */
-    static Rule evaluateRules(List<Rule> rules, AppInstallMetadata appInstallMetadata) {
+    @NonNull
+    static IntegrityCheckResult evaluateRules(
+            List<Rule> rules, AppInstallMetadata appInstallMetadata) {
+        List<Rule> matchedRules = new ArrayList<>();
         for (Rule rule : rules) {
-            if (isConjunctionOfFormulas(rule.getFormula()) && isMatch(rule, appInstallMetadata)) {
-                return rule;
-            }
-        }
-        return Rule.EMPTY;
-    }
-
-    /**
-     * Match a rule against app install metadata.
-     */
-    private static boolean isMatch(Rule rule, AppInstallMetadata appInstallMetadata) {
-        return isMatch(rule.getFormula(), appInstallMetadata);
-    }
-
-    private static boolean isMatch(Formula formula, AppInstallMetadata appInstallMetadata) {
-        if (formula instanceof AtomicFormula) {
-            AtomicFormula atomicFormula = (AtomicFormula) formula;
-            switch (atomicFormula.getKey()) {
-                case PACKAGE_NAME:
-                    return atomicFormula.isMatch(appInstallMetadata.getPackageName());
-                case APP_CERTIFICATE:
-                    return atomicFormula.isMatch(appInstallMetadata.getAppCertificate());
-                case INSTALLER_NAME:
-                    return atomicFormula.isMatch(appInstallMetadata.getInstallerName());
-                case INSTALLER_CERTIFICATE:
-                    return atomicFormula.isMatch(appInstallMetadata.getInstallerCertificate());
-                case VERSION_CODE:
-                    return atomicFormula.isMatch(appInstallMetadata.getVersionCode());
-                case PRE_INSTALLED:
-                    return atomicFormula.isMatch(appInstallMetadata.isPreInstalled());
-                default:
-                    Slog.i(TAG, String.format("Returned no match for unknown key %s",
-                            atomicFormula.getKey()));
-                    return false;
-            }
-        } else if (formula instanceof OpenFormula) {
-            OpenFormula openFormula = (OpenFormula) formula;
-            // A rule is in disjunctive normal form, so there are no OR connectors.
-            switch (openFormula.getConnector()) {
-                case NOT:
-                    // NOT connector has only 1 formula attached.
-                    return !isMatch(openFormula.getFormulas().get(0), appInstallMetadata);
-                case AND:
-                    return openFormula.getFormulas().stream().allMatch(
-                            subFormula -> isMatch(subFormula, appInstallMetadata));
-                default:
-                    Slog.i(TAG, String.format("Returned no match for unknown connector %s",
-                            openFormula.getConnector()));
-                    return false;
+            if (isConjunctionOfFormulas(rule.getFormula())
+                    && rule.getFormula().isSatisfied(appInstallMetadata)) {
+                matchedRules.add(rule);
             }
         }
 
-        return false;
+        boolean denied = false;
+        Rule denyRule = null;
+        for (Rule rule : matchedRules) {
+            switch (rule.getEffect()) {
+                case DENY:
+                    if (!denied) {
+                        denied = true;
+                        denyRule = rule;
+                    }
+                    break;
+                case FORCE_ALLOW:
+                    return IntegrityCheckResult.allow(rule);
+                default:
+                    Slog.e(TAG, "Matched an unknown effect rule: " + rule);
+                    return IntegrityCheckResult.allow();
+            }
+        }
+        return denied ? IntegrityCheckResult.deny(denyRule) : IntegrityCheckResult.allow();
     }
 
     private static boolean isConjunctionOfFormulas(Formula formula) {
@@ -111,7 +90,7 @@
             return true;
         }
         OpenFormula openFormula = (OpenFormula) formula;
-        return openFormula.getConnector() == OpenFormula.Connector.AND
+        return openFormula.getConnector() == OpenFormula.AND
                 && openFormula.getFormulas().stream().allMatch(RuleEvaluator::isAtomicFormula);
     }
 
@@ -120,7 +99,7 @@
             return true;
         }
         OpenFormula openFormula = (OpenFormula) formula;
-        return openFormula.getConnector() == OpenFormula.Connector.NOT
+        return openFormula.getConnector() == OpenFormula.NOT
                 && openFormula.getFormulas().get(0) instanceof AtomicFormula;
     }
 }
diff --git a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
index 660bd2e..dfc373b 100644
--- a/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
+++ b/services/core/java/com/android/server/integrity/model/AppInstallMetadata.java
@@ -19,7 +19,11 @@
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
+
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * The app install metadata.
@@ -28,7 +32,11 @@
  * to the rule evaluation engine to evaluate the metadata against the rules.
  *
  * <p>Instances of this class are immutable.
+ *
+ * @hide
  */
+@SystemApi
+@VisibleForTesting
 public final class AppInstallMetadata {
     private final String mPackageName;
     // Raw string encoding for the SHA-256 hash of the certificate of the app.
@@ -48,10 +56,12 @@
         this.mIsPreInstalled = builder.mIsPreInstalled;
     }
 
+    @NonNull
     public String getPackageName() {
         return mPackageName;
     }
 
+    @NonNull
     public String getAppCertificate() {
         return mAppCertificate;
     }
@@ -66,23 +76,17 @@
         return mInstallerCertificate;
     }
 
-    /**
-     * @see AppInstallMetadata.Builder#setVersionCode(int)
-     */
+    /** @see AppInstallMetadata.Builder#setVersionCode(int) */
     public int getVersionCode() {
         return mVersionCode;
     }
 
-    /**
-     * @see AppInstallMetadata.Builder#setIsPreInstalled(boolean)
-     */
+    /** @see AppInstallMetadata.Builder#setIsPreInstalled(boolean) */
     public boolean isPreInstalled() {
         return mIsPreInstalled;
     }
 
-    /**
-     * Builder class for constructing {@link AppInstallMetadata} objects.
-     */
+    /** Builder class for constructing {@link AppInstallMetadata} objects. */
     public static final class Builder {
         private String mPackageName;
         private String mAppCertificate;
@@ -96,7 +100,8 @@
          *
          * @see AppInstallMetadata#getPackageName()
          */
-        public Builder setPackageName(String packageName) {
+        @NonNull
+        public Builder setPackageName(@NonNull String packageName) {
             this.mPackageName = checkNotNull(packageName);
             return this;
         }
@@ -109,7 +114,8 @@
          *
          * @see AppInstallMetadata#getAppCertificate()
          */
-        public Builder setAppCertificate(String appCertificate) {
+        @NonNull
+        public Builder setAppCertificate(@NonNull String appCertificate) {
             this.mAppCertificate = checkNotNull(appCertificate);
             return this;
         }
@@ -119,7 +125,8 @@
          *
          * @see AppInstallMetadata#getInstallerName()
          */
-        public Builder setInstallerName(String installerName) {
+        @NonNull
+        public Builder setInstallerName(@NonNull String installerName) {
             this.mInstallerName = checkNotNull(installerName);
             return this;
         }
@@ -132,7 +139,8 @@
          *
          * @see AppInstallMetadata#getInstallerCertificate()
          */
-        public Builder setInstallerCertificate(String installerCertificate) {
+        @NonNull
+        public Builder setInstallerCertificate(@NonNull String installerCertificate) {
             this.mInstallerCertificate = checkNotNull(installerCertificate);
             return this;
         }
@@ -142,6 +150,7 @@
          *
          * @see AppInstallMetadata#getVersionCode()
          */
+        @NonNull
         public Builder setVersionCode(int versionCode) {
             this.mVersionCode = versionCode;
             return this;
@@ -152,6 +161,7 @@
          *
          * @see AppInstallMetadata#isPreInstalled()
          */
+        @NonNull
         public Builder setIsPreInstalled(boolean isPreInstalled) {
             this.mIsPreInstalled = isPreInstalled;
             return this;
@@ -159,7 +169,10 @@
 
         /**
          * Build {@link AppInstallMetadata}.
+         *
+         * @throws IllegalArgumentException if package name or app certificate is null
          */
+        @NonNull
         public AppInstallMetadata build() {
             checkArgument(mPackageName != null);
             checkArgument(mAppCertificate != null);
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 b9b46e3..70ab98c 100644
--- a/services/core/java/com/android/server/integrity/model/AtomicFormula.java
+++ b/services/core/java/com/android/server/integrity/model/AtomicFormula.java
@@ -17,220 +17,420 @@
 package com.android.server.integrity.model;
 
 import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
-import android.annotation.Nullable;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Represents a simple formula consisting of an app install metadata field and a value.
  *
  * <p>Instances of this class are immutable.
+ *
+ * @hide
  */
-public final class AtomicFormula extends Formula {
+@SystemApi
+@VisibleForTesting
+public abstract class AtomicFormula implements Formula {
 
     private static final String TAG = "AtomicFormula";
 
-    public enum Key {
-        PACKAGE_NAME,
-        APP_CERTIFICATE,
-        INSTALLER_NAME,
-        INSTALLER_CERTIFICATE,
-        VERSION_CODE,
-        PRE_INSTALLED
+    @IntDef(
+            value = {
+                    PACKAGE_NAME,
+                    APP_CERTIFICATE,
+                    INSTALLER_NAME,
+                    INSTALLER_CERTIFICATE,
+                    VERSION_CODE,
+                    PRE_INSTALLED,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Key {}
+
+    @IntDef(value = {EQ, LT, LE, GT, GE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Operator {}
+
+    public static final int PACKAGE_NAME = 0;
+    public static final int APP_CERTIFICATE = 1;
+    public static final int INSTALLER_NAME = 2;
+    public static final int INSTALLER_CERTIFICATE = 3;
+    public static final int VERSION_CODE = 4;
+    public static final int PRE_INSTALLED = 5;
+
+    public static final int EQ = 0;
+    public static final int LT = 1;
+    public static final int LE = 2;
+    public static final int GT = 3;
+    public static final int GE = 4;
+
+    private final @Key int mKey;
+
+    public AtomicFormula(@Key int key) {
+        mKey = key;
     }
 
-    public enum Operator {
-        EQ,
-        LT,
-        LE,
-        GT,
-        GE
+    /** An {@link AtomicFormula} with an key and int value. */
+    public static final class IntAtomicFormula extends AtomicFormula implements Parcelable {
+        private final int mValue;
+        private final @Operator int mOperator;
+
+        /**
+         * Constructs a new {@link IntAtomicFormula}.
+         *
+         * <p>This formula will hold if and only if the corresponding information of an install
+         * specified by {@code key} is of the correct relationship to {@code value} as specified by
+         * {@code operator}.
+         *
+         * @throws IllegalArgumentException if {@code key} is not {@link #VERSION_CODE}
+         */
+        public IntAtomicFormula(@Key int key, @Operator int operator, int value) {
+            super(key);
+            checkArgument(
+                    key == VERSION_CODE,
+                    String.format("Key %s cannot be used with IntAtomicFormula", keyToString(key)));
+            mOperator = operator;
+            mValue = value;
+        }
+
+        IntAtomicFormula(Parcel in) {
+            super(in.readInt());
+            mValue = in.readInt();
+            mOperator = in.readInt();
+        }
+
+        @NonNull
+        public static final Creator<IntAtomicFormula> CREATOR =
+                new Creator<IntAtomicFormula>() {
+                    @Override
+                    public IntAtomicFormula createFromParcel(Parcel in) {
+                        return new IntAtomicFormula(in);
+                    }
+
+                    @Override
+                    public IntAtomicFormula[] newArray(int size) {
+                        return new IntAtomicFormula[size];
+                    }
+                };
+
+        @Override
+        public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+            int metadataValue = getMetadataValueByKey(appInstallMetadata);
+            switch (mOperator) {
+                case EQ:
+                    return metadataValue == mValue;
+                case LE:
+                    return metadataValue <= mValue;
+                case LT:
+                    return metadataValue < mValue;
+                case GE:
+                    return metadataValue >= mValue;
+                case GT:
+                    return metadataValue > mValue;
+                default:
+                    Slog.i(TAG, String.format("Unexpected operator %d", mOperator));
+                    return false;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format(
+                    "(%s %s %s)", keyToString(getKey()), operatorToString(mOperator), mValue);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            IntAtomicFormula that = (IntAtomicFormula) o;
+            return getKey() == that.getKey() && mValue == that.mValue;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getKey(), mOperator, mValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeInt(getKey());
+            dest.writeInt(mValue);
+            dest.writeInt(mOperator);
+        }
+
+        public int getValue() {
+            return mValue;
+        }
+
+        public int getOperator() {
+            return mOperator;
+        }
+
+        private int getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+            switch (getKey()) {
+                case VERSION_CODE:
+                    return appInstallMetadata.getVersionCode();
+                default:
+                    throw new IllegalStateException(
+                            "Unexpected key in IntAtomicFormula" + getKey());
+            }
+        }
     }
 
-    private final Key mKey;
-    private final Operator mOperator;
+    /** An {@link AtomicFormula} with a key and string value. */
+    public static final class StringAtomicFormula extends AtomicFormula implements Parcelable {
+        private final String mValue;
 
-    // The value of a key can take either 1 of 3 forms: String, Integer, or Boolean.
-    // It cannot have multiple values.
-    @Nullable
-    private final String mStringValue;
-    @Nullable
-    private final Integer mIntValue;
-    @Nullable
-    private final Boolean mBoolValue;
+        /**
+         * Constructs a new {@link StringAtomicFormula}.
+         *
+         * <p>This formula will hold if and only if the corresponding information of an install
+         * specified by {@code key} equals {@code value}.
+         *
+         * @throws IllegalArgumentException if {@code key} is not one of {@link #PACKAGE_NAME},
+         *     {@link #APP_CERTIFICATE}, {@link #INSTALLER_NAME} and {@link #INSTALLER_CERTIFICATE}
+         */
+        public StringAtomicFormula(@Key int key, @NonNull String value) {
+            super(key);
+            checkArgument(
+                    key == PACKAGE_NAME
+                            || key == APP_CERTIFICATE
+                            || key == INSTALLER_CERTIFICATE
+                            || key == INSTALLER_NAME,
+                    String.format(
+                            "Key %s cannot be used with StringAtomicFormula", keyToString(key)));
+            mValue = value;
+        }
 
-    public AtomicFormula(Key key, Operator operator, String stringValue) {
-        validateOperator(key, operator);
-        checkArgument(
-                key == Key.PACKAGE_NAME || key == Key.APP_CERTIFICATE || key == Key.INSTALLER_NAME
-                        || key == Key.INSTALLER_CERTIFICATE,
-                String.format("Key %s cannot have string value", key));
-        this.mKey = checkNotNull(key);
-        this.mOperator = checkNotNull(operator);
-        this.mStringValue = checkNotNull(stringValue);
-        this.mIntValue = null;
-        this.mBoolValue = null;
+        StringAtomicFormula(Parcel in) {
+            super(in.readInt());
+            mValue = in.readStringNoHelper();
+        }
+
+        @NonNull
+        public static final Creator<StringAtomicFormula> CREATOR =
+                new Creator<StringAtomicFormula>() {
+                    @Override
+                    public StringAtomicFormula createFromParcel(Parcel in) {
+                        return new StringAtomicFormula(in);
+                    }
+
+                    @Override
+                    public StringAtomicFormula[] newArray(int size) {
+                        return new StringAtomicFormula[size];
+                    }
+                };
+
+        @Override
+        public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+            String metadataValue = getMetadataValueByKey(appInstallMetadata);
+            return metadataValue.equals(mValue);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            StringAtomicFormula that = (StringAtomicFormula) o;
+            return getKey() == that.getKey() && Objects.equals(mValue, that.mValue);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getKey(), mValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeInt(getKey());
+            dest.writeStringNoHelper(mValue);
+        }
+
+        public String getValue() {
+            return mValue;
+        }
+
+        private String getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+            switch (getKey()) {
+                case PACKAGE_NAME:
+                    return appInstallMetadata.getPackageName();
+                case APP_CERTIFICATE:
+                    return appInstallMetadata.getAppCertificate();
+                case INSTALLER_CERTIFICATE:
+                    return appInstallMetadata.getInstallerCertificate();
+                case INSTALLER_NAME:
+                    return appInstallMetadata.getInstallerName();
+                default:
+                    throw new IllegalStateException(
+                            "Unexpected key in StringAtomicFormula: " + getKey());
+            }
+        }
     }
 
-    public AtomicFormula(Key key, Operator operator, Integer intValue) {
-        validateOperator(key, operator);
-        checkArgument(key == Key.VERSION_CODE,
-                String.format("Key %s cannot have integer value", key));
-        this.mKey = checkNotNull(key);
-        this.mOperator = checkNotNull(operator);
-        this.mStringValue = null;
-        this.mIntValue = checkNotNull(intValue);
-        this.mBoolValue = null;
+    /** An {@link AtomicFormula} with a key and boolean value. */
+    public static final class BooleanAtomicFormula extends AtomicFormula implements Parcelable {
+        private final boolean mValue;
+
+        /**
+         * Constructs a new {@link BooleanAtomicFormula}.
+         *
+         * <p>This formula will hold if and only if the corresponding information of an install
+         * specified by {@code key} equals {@code value}.
+         *
+         * @throws IllegalArgumentException if {@code key} is not {@link #PRE_INSTALLED}
+         */
+        public BooleanAtomicFormula(@Key int key, boolean value) {
+            super(key);
+            checkArgument(
+                    key == PRE_INSTALLED,
+                    String.format(
+                            "Key %s cannot be used with BooleanAtomicFormula", keyToString(key)));
+            mValue = value;
+        }
+
+        BooleanAtomicFormula(Parcel in) {
+            super(in.readInt());
+            mValue = in.readByte() != 0;
+        }
+
+        @NonNull
+        public static final Creator<BooleanAtomicFormula> CREATOR =
+                new Creator<BooleanAtomicFormula>() {
+                    @Override
+                    public BooleanAtomicFormula createFromParcel(Parcel in) {
+                        return new BooleanAtomicFormula(in);
+                    }
+
+                    @Override
+                    public BooleanAtomicFormula[] newArray(int size) {
+                        return new BooleanAtomicFormula[size];
+                    }
+                };
+
+        @Override
+        public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+            boolean metadataValue = getMetadataValueByKey(appInstallMetadata);
+            return metadataValue == mValue;
+        }
+
+        @Override
+        public String toString() {
+            return String.format("(%s %s %s)", keyToString(getKey()), operatorToString(EQ), mValue);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            BooleanAtomicFormula that = (BooleanAtomicFormula) o;
+            return getKey() == that.getKey() && mValue == that.mValue;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(getKey(), mValue);
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeInt(getKey());
+            dest.writeByte((byte) (mValue ? 1 : 0));
+        }
+
+        public boolean getValue() {
+            return mValue;
+        }
+
+        private boolean getMetadataValueByKey(AppInstallMetadata appInstallMetadata) {
+            switch (getKey()) {
+                case PRE_INSTALLED:
+                    return appInstallMetadata.isPreInstalled();
+                default:
+                    throw new IllegalStateException(
+                            "Unexpected key in BooleanAtomicFormula: " + getKey());
+            }
+        }
     }
 
-    public AtomicFormula(Key key, Operator operator, Boolean boolValue) {
-        validateOperator(key, operator);
-        checkArgument(key == Key.PRE_INSTALLED,
-                String.format("Key %s cannot have boolean value", key));
-        this.mKey = checkNotNull(key);
-        this.mOperator = checkNotNull(operator);
-        this.mStringValue = null;
-        this.mIntValue = null;
-        this.mBoolValue = checkNotNull(boolValue);
-    }
-
-    public Key getKey() {
+    public int getKey() {
         return mKey;
     }
 
-    public Operator getOperator() {
-        return mOperator;
-    }
-
-    public String getStringValue() {
-        return mStringValue;
-    }
-
-    public Integer getIntValue() {
-        return mIntValue;
-    }
-
-    public Boolean getBoolValue() {
-        return mBoolValue;
-    }
-
-    /**
-     * Get string representation of the value of the key in the formula.
-     *
-     * @return string representation of the value of the key.
-     */
-    public String getValue() {
-        if (mStringValue != null) {
-            return mStringValue;
-        }
-        if (mIntValue != null) {
-            return mIntValue.toString();
-        }
-        return mBoolValue.toString();
-    }
-
-    /**
-     * Check if the formula is true when substituting its {@link Key} with the string value.
-     *
-     * @param value String value to substitute the key with.
-     * @return {@code true} if the formula is true, and {@code false} otherwise.
-     */
-    public boolean isMatch(String value) {
-        switch (mOperator) {
-            case EQ:
-                return mStringValue.equals(value);
-        }
-        Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mStringValue));
-        return false;
-    }
-
-    /**
-     * Check if the formula is true when substituting its {@link Key} with the integer value.
-     *
-     * @param value Integer value to substitute the key with.
-     * @return {@code true} if the formula is true, and {@code false} otherwise.
-     */
-    public boolean isMatch(int value) {
-        switch (mOperator) {
-            case EQ:
-                return mIntValue == value;
-            case LE:
-                return mIntValue <= value;
-            case LT:
-                return mIntValue < value;
-            case GE:
-                return mIntValue >= value;
-            case GT:
-                return mIntValue > value;
-        }
-        Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mIntValue));
-        return false;
-    }
-
-    /**
-     * Check if the formula is true when substituting its {@link Key} with the boolean value.
-     *
-     * @param value Boolean value to substitute the key with.
-     * @return {@code true} if the formula is true, and {@code false} otherwise.
-     */
-    public boolean isMatch(boolean value) {
-        switch (mOperator) {
-            case EQ:
-                return mBoolValue == value;
-        }
-        Slog.i(TAG, String.format("Found operator %s for value %s", mOperator, mBoolValue));
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return String.format("%s %s %s", mKey, mOperator, getValue());
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-        if (o == null || getClass() != o.getClass()) {
-            return false;
-        }
-        AtomicFormula that = (AtomicFormula) o;
-        return mKey == that.mKey
-                && mOperator == that.mOperator
-                && Objects.equals(mStringValue, that.mStringValue)
-                && Objects.equals(mIntValue, that.mIntValue)
-                && Objects.equals(mBoolValue, that.mBoolValue);
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(mKey, mOperator, mStringValue, mIntValue, mBoolValue);
-    }
-
-    private void validateOperator(Key key, Operator operator) {
-        boolean validOperator;
+    String keyToString(int key) {
         switch (key) {
             case PACKAGE_NAME:
+                return "PACKAGE_NAME";
             case APP_CERTIFICATE:
-            case INSTALLER_NAME:
-            case INSTALLER_CERTIFICATE:
-            case PRE_INSTALLED:
-                validOperator = (operator == Operator.EQ);
-                break;
+                return "APP_CERTIFICATE";
             case VERSION_CODE:
-                validOperator = true;
-                break;
+                return "VERSION_CODE";
+            case INSTALLER_NAME:
+                return "INSTALLER_NAME";
+            case INSTALLER_CERTIFICATE:
+                return "INSTALLER_CERTIFICATE";
+            case PRE_INSTALLED:
+                return "PRE_INSTALLED";
             default:
-                Slog.i(TAG, String.format("Found operator %s for key %s", operator, key));
-                validOperator = false;
+                throw new IllegalArgumentException("Unknown key " + key);
         }
-        if (!validOperator) {
-            throw new IllegalArgumentException(
-                    String.format("Invalid operator %s used for key %s", operator, key));
+    }
+
+    String operatorToString(int op) {
+        switch (op) {
+            case EQ:
+                return "EQ";
+            case LT:
+                return "LT";
+            case LE:
+                return "LE";
+            case GT:
+                return "GT";
+            case GE:
+                return "GE";
+            default:
+                throw new IllegalArgumentException("Unknown operator " + op);
         }
     }
 }
diff --git a/services/core/java/com/android/server/integrity/model/Formula.java b/services/core/java/com/android/server/integrity/model/Formula.java
index 9db4453..852ece5 100644
--- a/services/core/java/com/android/server/integrity/model/Formula.java
+++ b/services/core/java/com/android/server/integrity/model/Formula.java
@@ -16,9 +16,84 @@
 
 package com.android.server.integrity.model;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
+
 /**
  * Represents a rule logic/content.
+ *
+ * @hide
  */
-public abstract class Formula {
+@SystemApi
+@VisibleForTesting
+public interface Formula {
 
+    int OPEN_FORMULA_TAG = 0;
+    int STRING_ATOMIC_FORMULA_TAG = 1;
+    int INT_ATOMIC_FORMULA_TAG = 2;
+    int BOOLEAN_ATOMIC_FORMULA_TAG = 3;
+
+    /**
+     * Returns if this formula can be satisfied by substituting the corresponding information of
+     * {@code appInstallMetadata} into the formula.
+     */
+    boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata);
+
+    /**
+     * Write a {@link Formula} to {@link android.os.Parcel}.
+     *
+     * <p>This helper method is needed because non-final class/interface are not allowed to be
+     * {@link Parcelable}.
+     *
+     * @throws IllegalArgumentException if {@link Formula} is not a recognized subclass
+     */
+    static void writeToParcel(@NonNull Formula formula, @NonNull Parcel dest, int flags) {
+        if (formula instanceof OpenFormula) {
+            dest.writeInt(OPEN_FORMULA_TAG);
+            ((OpenFormula) formula).writeToParcel(dest, flags);
+        } else if (formula instanceof StringAtomicFormula) {
+            dest.writeInt(STRING_ATOMIC_FORMULA_TAG);
+            ((StringAtomicFormula) formula).writeToParcel(dest, flags);
+        } else if (formula instanceof IntAtomicFormula) {
+            dest.writeInt(INT_ATOMIC_FORMULA_TAG);
+            ((IntAtomicFormula) formula).writeToParcel(dest, flags);
+        } else if (formula instanceof BooleanAtomicFormula) {
+            dest.writeInt(BOOLEAN_ATOMIC_FORMULA_TAG);
+            ((BooleanAtomicFormula) formula).writeToParcel(dest, flags);
+        } else {
+            throw new IllegalArgumentException("Unrecognized class " + formula.getClass());
+        }
+    }
+
+    /**
+     * Read a {@link Formula} from a {@link android.os.Parcel}.
+     *
+     * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link
+     * Parcelable} (api lint error).
+     *
+     * @throws IllegalArgumentException if the parcel cannot be parsed
+     */
+    @NonNull
+    static Formula readFromParcel(@NonNull Parcel in) {
+        int tag = in.readInt();
+        switch (tag) {
+            case OPEN_FORMULA_TAG:
+                return OpenFormula.CREATOR.createFromParcel(in);
+            case STRING_ATOMIC_FORMULA_TAG:
+                return StringAtomicFormula.CREATOR.createFromParcel(in);
+            case INT_ATOMIC_FORMULA_TAG:
+                return IntAtomicFormula.CREATOR.createFromParcel(in);
+            case BOOLEAN_ATOMIC_FORMULA_TAG:
+                return BooleanAtomicFormula.CREATOR.createFromParcel(in);
+            default:
+                throw new IllegalArgumentException("Unknown formula tag " + tag);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
index 7aeb0c1..ef0751d 100644
--- a/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
+++ b/services/core/java/com/android/server/integrity/model/IntegrityCheckResult.java
@@ -16,6 +16,8 @@
 
 package com.android.server.integrity.model;
 
+import android.annotation.Nullable;
+
 /**
  * A class encapsulating the result from the evaluation engine after evaluating rules against app
  * install metadata.
@@ -31,9 +33,9 @@
     }
 
     private final Effect mEffect;
-    private final Rule mRule;
+    @Nullable private final Rule mRule;
 
-    private IntegrityCheckResult(Effect effect, Rule rule) {
+    private IntegrityCheckResult(Effect effect, @Nullable Rule rule) {
         this.mEffect = effect;
         this.mRule = rule;
     }
@@ -49,10 +51,19 @@
     /**
      * Create an ALLOW evaluation outcome.
      *
-     * @return An evaluation outcome with ALLOW effect and empty rule.
+     * @return An evaluation outcome with ALLOW effect and no rule.
      */
     public static IntegrityCheckResult allow() {
-        return new IntegrityCheckResult(Effect.ALLOW, Rule.EMPTY);
+        return new IntegrityCheckResult(Effect.ALLOW, null);
+    }
+
+    /**
+     * Create an ALLOW evaluation outcome.
+     *
+     * @return An evaluation outcome with ALLOW effect and rule causing that effect.
+     */
+    public static IntegrityCheckResult allow(Rule rule) {
+        return new IntegrityCheckResult(Effect.ALLOW, rule);
     }
 
     /**
diff --git a/services/core/java/com/android/server/integrity/model/OpenFormula.java b/services/core/java/com/android/server/integrity/model/OpenFormula.java
index 21da629..f29706a 100644
--- a/services/core/java/com/android/server/integrity/model/OpenFormula.java
+++ b/services/core/java/com/android/server/integrity/model/OpenFormula.java
@@ -17,8 +17,19 @@
 package com.android.server.integrity.model;
 
 import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -27,40 +38,108 @@
  * Represents a complex formula consisting of other simple and complex formulas.
  *
  * <p>Instances of this class are immutable.
+ *
+ * @hide
  */
-public final class OpenFormula extends Formula {
+@SystemApi
+@VisibleForTesting
+public final class OpenFormula implements Formula, Parcelable {
+    private static final String TAG = "OpenFormula";
 
-    public enum Connector {
-        AND,
-        OR,
-        NOT
-    }
+    @IntDef(
+            value = {
+                    AND, OR, NOT,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Connector {}
 
-    private final Connector mConnector;
+    /** Boolean AND operator. */
+    public static final int AND = 0;
+
+    /** Boolean OR operator. */
+    public static final int OR = 1;
+
+    /** Boolean NOT operator. */
+    public static final int NOT = 2;
+
+    private final @Connector int mConnector;
     private final List<Formula> mFormulas;
 
-    public OpenFormula(Connector connector, List<Formula> formulas) {
+    @NonNull
+    public static final Creator<OpenFormula> CREATOR =
+            new Creator<OpenFormula>() {
+                @Override
+                public OpenFormula createFromParcel(Parcel in) {
+                    return new OpenFormula(in);
+                }
+
+                @Override
+                public OpenFormula[] newArray(int size) {
+                    return new OpenFormula[size];
+                }
+            };
+
+    /**
+     * Create a new formula from operator and operands.
+     *
+     * @throws IllegalArgumentException if the number of operands is not matching the requirements
+     *     for that operator (at least 2 for {@link #AND} and {@link #OR}, 1 for {@link #NOT}).
+     */
+    public OpenFormula(@Connector int connector, @NonNull List<Formula> formulas) {
         validateFormulas(connector, formulas);
-        this.mConnector = checkNotNull(connector);
-        this.mFormulas = Collections.unmodifiableList(checkNotNull(formulas));
+        this.mConnector = connector;
+        this.mFormulas = Collections.unmodifiableList(formulas);
     }
 
-    public Connector getConnector() {
+    OpenFormula(Parcel in) {
+        mConnector = in.readInt();
+        int length = in.readInt();
+        checkArgument(length >= 0, "Must have non-negative length. Got " + length);
+        mFormulas = new ArrayList<>(length);
+        for (int i = 0; i < length; i++) {
+            mFormulas.add(Formula.readFromParcel(in));
+        }
+    }
+
+    public @Connector int getConnector() {
         return mConnector;
     }
 
+    @NonNull
     public List<Formula> getFormulas() {
         return mFormulas;
     }
 
     @Override
+    public boolean isSatisfied(@NonNull AppInstallMetadata appInstallMetadata) {
+        switch (mConnector) {
+            case NOT:
+                return !mFormulas.get(0).isSatisfied(appInstallMetadata);
+            case AND:
+                return mFormulas.stream()
+                        .allMatch(formula -> formula.isSatisfied(appInstallMetadata));
+            case OR:
+                return mFormulas.stream()
+                        .anyMatch(formula -> formula.isSatisfied(appInstallMetadata));
+            default:
+                Slog.i(TAG, "Unknown connector " + mConnector);
+                return false;
+        }
+    }
+
+    @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < mFormulas.size(); i++) {
-            if (i > 0) {
-                sb.append(String.format(" %s ", mConnector));
+        if (mFormulas.size() == 1) {
+            sb.append(String.format("%s ", connectorToString(mConnector)));
+            sb.append(mFormulas.get(0).toString());
+        } else {
+            for (int i = 0; i < mFormulas.size(); i++) {
+                if (i > 0) {
+                    sb.append(String.format(" %s ", connectorToString(mConnector)));
+                }
+                sb.append(mFormulas.get(i).toString());
             }
-            sb.append(mFormulas.get(i).toString());
         }
         return sb.toString();
     }
@@ -74,8 +153,7 @@
             return false;
         }
         OpenFormula that = (OpenFormula) o;
-        return mConnector == that.mConnector
-                && mFormulas.equals(that.mFormulas);
+        return mConnector == that.mConnector && mFormulas.equals(that.mFormulas);
     }
 
     @Override
@@ -83,17 +161,50 @@
         return Objects.hash(mConnector, mFormulas);
     }
 
-    private void validateFormulas(Connector connector, List<Formula> formulas) {
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mConnector);
+        dest.writeInt(mFormulas.size());
+        for (Formula formula : mFormulas) {
+            Formula.writeToParcel(formula, dest, flags);
+        }
+    }
+
+    private void validateFormulas(@Connector int connector, List<Formula> formulas) {
         switch (connector) {
             case AND:
             case OR:
-                checkArgument(formulas.size() >= 2,
-                        String.format("Connector %s must have at least 2 formulas", connector));
+                checkArgument(
+                        formulas.size() >= 2,
+                        String.format(
+                                "Connector %s must have at least 2 formulas",
+                                connectorToString(connector)));
                 break;
             case NOT:
-                checkArgument(formulas.size() == 1,
-                        String.format("Connector %s must have 1 formula only", connector));
+                checkArgument(
+                        formulas.size() == 1,
+                        String.format(
+                                "Connector %s must have 1 formula only",
+                                connectorToString(connector)));
                 break;
         }
     }
+
+    private String connectorToString(int connector) {
+        switch (connector) {
+            case AND:
+                return "AND";
+            case OR:
+                return "OR";
+            case NOT:
+                return "NOT";
+            default:
+                throw new IllegalArgumentException("Unknown connector " + connector);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/integrity/model/Rule.java b/services/core/java/com/android/server/integrity/model/Rule.java
index 63b9b91..14dcb26 100644
--- a/services/core/java/com/android/server/integrity/model/Rule.java
+++ b/services/core/java/com/android/server/integrity/model/Rule.java
@@ -18,55 +18,96 @@
 
 import static com.android.internal.util.Preconditions.checkNotNull;
 
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Represent rules to be used in the rule evaluation engine to match against app installs.
  *
  * <p>Instances of this class are immutable.
+ *
+ * @hide
  */
-public final class Rule {
+@SystemApi
+@VisibleForTesting
+public final class Rule implements Parcelable {
 
-    public enum Effect {
-        DENY
-    }
+    @IntDef(
+            value = {
+                DENY,
+                FORCE_ALLOW,
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Effect {}
 
-    // Holds an empty rule instance.
-    public static final Rule EMPTY = new Rule();
-
-    private final Formula mFormula;
-    private final Effect mEffect;
-
-    private Rule() {
-        this.mFormula = null;
-        this.mEffect = null;
-    }
-
-    public Rule(Formula formula, Effect effect) {
-        this.mFormula = checkNotNull(formula);
-        this.mEffect = checkNotNull(effect);
-    }
+    /** If this rule matches the install, the install should be denied. */
+    public static final int DENY = 0;
 
     /**
-     * Indicates whether the rule is empty or not.
-     *
-     * @return {@code true} if the rule is empty, and {@code false} otherwise.
+     * If this rule matches the install, the install will be allowed regardless of other matched
+     * rules.
      */
-    public boolean isEmpty() {
-        return mFormula == null && mEffect == null;
+    public static final int FORCE_ALLOW = 1;
+
+    private final Formula mFormula;
+    private final @Effect int mEffect;
+
+    public Rule(@NonNull Formula formula, @Effect int effect) {
+        this.mFormula = checkNotNull(formula);
+        this.mEffect = effect;
     }
 
+    Rule(Parcel in) {
+        mFormula = Formula.readFromParcel(in);
+        mEffect = in.readInt();
+    }
+
+    @NonNull
+    public static final Creator<Rule> CREATOR =
+            new Creator<Rule>() {
+                @Override
+                public Rule createFromParcel(Parcel in) {
+                    return new Rule(in);
+                }
+
+                @Override
+                public Rule[] newArray(int size) {
+                    return new Rule[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        Formula.writeToParcel(mFormula, dest, flags);
+        dest.writeInt(mEffect);
+    }
+
+    @NonNull
     public Formula getFormula() {
         return mFormula;
     }
 
-    public Effect getEffect() {
+    public @Effect int getEffect() {
         return mEffect;
     }
 
     @Override
     public String toString() {
-        return String.format("Rule: %s, %s", mFormula, mEffect);
+        return String.format("Rule: %s, %s", mFormula, effectToString(mEffect));
     }
 
     @Override
@@ -78,12 +119,22 @@
             return false;
         }
         Rule that = (Rule) o;
-        return Objects.equals(mFormula, that.mFormula)
-                && Objects.equals(mEffect, that.mEffect);
+        return Objects.equals(mFormula, that.mFormula) && mEffect == that.mEffect;
     }
 
     @Override
     public int hashCode() {
         return Objects.hash(mFormula, mEffect);
     }
+
+    private String effectToString(int effect) {
+        switch (effect) {
+            case DENY:
+                return "DENY";
+            case FORCE_ALLOW:
+                return "FORCE_ALLOW";
+            default:
+                throw new IllegalArgumentException("Unknown effect " + effect);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
index c1567bc..5ed282c 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleBinaryParser.java
@@ -19,18 +19,19 @@
 import com.android.server.integrity.model.Rule;
 
 import java.io.InputStream;
+import java.util.List;
 
 /** A helper class to parse rules into the {@link Rule} model from Binary representation. */
 public class RuleBinaryParser implements RuleParser {
 
     @Override
-    public Rule parse(String ruleText) {
+    public List<Rule> parse(String ruleText) {
         // TODO: Implement binary text parser.
         return null;
     }
 
     @Override
-    public Rule parse(InputStream inputStream) {
+    public List<Rule> parse(InputStream inputStream) {
         // TODO: Implement stream parser.
         return null;
     }
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 96ed5993..08e0a5d 100644
--- a/services/core/java/com/android/server/integrity/parser/RuleParser.java
+++ b/services/core/java/com/android/server/integrity/parser/RuleParser.java
@@ -19,13 +19,14 @@
 import com.android.server.integrity.model.Rule;
 
 import java.io.InputStream;
+import java.util.List;
 
 /** A helper class to parse rules into the {@link Rule} model. */
 public interface RuleParser {
 
     /** Parse rules from a string. */
-    Rule parse(String ruleText);
+    List<Rule> parse(String ruleText) throws RuleParseException;
 
     /** Parse rules from an input stream. */
-    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 8b1bec9..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,22 +16,232 @@
 
 package com.android.server.integrity.parser;
 
+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.InputStream;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
 
-/** A helper class to parse rules into the {@link Rule} model from Xml representation. */
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class to parse rules into the {@link Rule} model from Xml representation.
+ */
 public final class RuleXmlParser implements RuleParser {
 
+    public static final String TAG = "RuleXmlParser";
+
+    // 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 Rule parse(String ruleText) {
-        // TODO: Implement text parser.
-        return null;
+    public List<Rule> parse(String ruleText) throws RuleParseException {
+        try {
+            XmlPullParser xmlPullParser = Xml.newPullParser();
+            xmlPullParser.setInput(new StringReader(ruleText));
+            return parseRules(xmlPullParser);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
+        }
     }
 
     @Override
-    public Rule parse(InputStream inputStream) {
-        // TODO: Implement stream parser.
-        return null;
+    public List<Rule> parse(InputStream inputStream) throws RuleParseException {
+        try {
+            XmlPullParser xmlPullParser = Xml.newPullParser();
+            xmlPullParser.setInput(inputStream, StandardCharsets.UTF_8.name());
+            return parseRules(xmlPullParser);
+        } catch (Exception e) {
+            throw new RuleParseException(e.getMessage(), e);
+        }
+    }
+
+    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 <RL> tag.
+        String nodeName = parser.getName();
+        // 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 <RL> tag. Found: %s at %s",
+                            nodeName, parser.getPositionDescription()));
+        }
+
+        int eventType;
+        while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
+            nodeName = parser.getName();
+            if (eventType != XmlPullParser.START_TAG || !nodeName.equals(RULE_TAG)) {
+                continue;
+            }
+            rules.add(parseRule(parser));
+        }
+
+        return rules;
+    }
+
+    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/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index fb57d69..8d2fc17 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1482,39 +1482,35 @@
             Log.v(TAG, "SV count: " + info.mSvCount);
         }
         // Calculate number of satellites used in fix.
+        GnssStatus gnssStatus = GnssStatus.wrap(
+                info.mSvCount,
+                info.mSvidWithFlags,
+                info.mCn0s,
+                info.mSvElevations,
+                info.mSvAzimuths,
+                info.mSvCarrierFreqs);
         int usedInFixCount = 0;
         int maxCn0 = 0;
         int meanCn0 = 0;
-        for (int i = 0; i < info.mSvCount; i++) {
-            if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
+        for (int i = 0; i < gnssStatus.getSatelliteCount(); i++) {
+            if (gnssStatus.usedInFix(i)) {
                 ++usedInFixCount;
-                if (info.mCn0s[i] > maxCn0) {
-                    maxCn0 = (int) info.mCn0s[i];
+                if (gnssStatus.getCn0DbHz(i) > maxCn0) {
+                    maxCn0 = (int) gnssStatus.getCn0DbHz(i);
                 }
-                meanCn0 += info.mCn0s[i];
+                meanCn0 += gnssStatus.getCn0DbHz(i);
+                mGnssMetrics.logConstellationType(gnssStatus.getConstellationType(i));
             }
             if (VERBOSE) {
-                Log.v(TAG, "svid: " + (info.mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
-                        " cn0: " + info.mCn0s[i] +
-                        " elev: " + info.mSvElevations[i] +
-                        " azimuth: " + info.mSvAzimuths[i] +
-                        " carrier frequency: " + info.mSvCarrierFreqs[i] +
-                        ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
-                                ? "  " : " E") +
-                        ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
-                                ? "  " : " A") +
-                        ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
-                                ? "" : "U") +
-                        ((info.mSvidWithFlags[i] &
-                                GnssStatus.GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY) == 0
-                                ? "" : "F"));
-            }
-
-            if ((info.mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
-                int constellationType =
-                        (info.mSvidWithFlags[i] >> GnssStatus.CONSTELLATION_TYPE_SHIFT_WIDTH)
-                                & GnssStatus.CONSTELLATION_TYPE_MASK;
-                mGnssMetrics.logConstellationType(constellationType);
+                Log.v(TAG, "svid: " + gnssStatus.getSvid(i)
+                        + " cn0: " + gnssStatus.getCn0DbHz(i)
+                        + " elev: " + gnssStatus.getElevationDegrees(i)
+                        + " azimuth: " + gnssStatus.getAzimuthDegrees(i)
+                        + " carrier frequency: " + gnssStatus.getCn0DbHz(i)
+                        + (gnssStatus.hasEphemerisData(i) ? " E" : "  ")
+                        + (gnssStatus.hasAlmanacData(i) ? " A" : "  ")
+                        + (gnssStatus.usedInFix(i) ? "U" : "")
+                        + (gnssStatus.hasCarrierFrequencyHz(i) ? "F" : ""));
             }
         }
         if (usedInFixCount > 0) {
@@ -1523,7 +1519,7 @@
         // return number of sats used in fix instead of total reported
         mLocationExtras.set(usedInFixCount, meanCn0, maxCn0);
 
-        mGnssMetrics.logSvStatus(info.mSvCount, info.mSvidWithFlags, info.mSvCarrierFreqs);
+        mGnssMetrics.logSvStatus(gnssStatus);
     }
 
     @NativeEntryPoint
diff --git a/services/core/java/com/android/server/location/TEST_MAPPING b/services/core/java/com/android/server/location/TEST_MAPPING
deleted file mode 100644
index 2e21fa6..0000000
--- a/services/core/java/com/android/server/location/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "CtsLocationCoarseTestCases"
-    },
-    {
-      "name": "CtsLocationNoneTestCases"
-    }
-  ]
-}
\ No newline at end of file
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 44642d4..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));
         }
     }
 
@@ -469,10 +489,15 @@
             mAllManagerRecords.put(binder, managerRecord);
 
             userRecord.mHandler.sendMessage(
-                    obtainMessage(UserHandler::notifyProviderInfosUpdatedToManager,
+                    obtainMessage(UserHandler::notifyRoutesToManager,
                             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();
@@ -808,17 +846,20 @@
                 }
 
                 List<IMediaRouter2Client> clients = getClients();
+                List<IMediaRouter2Manager> managers = getManagers();
                 if (addedRoutes.size() > 0) {
                     notifyRoutesAddedToClients(clients, addedRoutes);
+                    notifyRoutesAddedToManagers(managers, addedRoutes);
                 }
                 if (removedRoutes.size() > 0) {
                     notifyRoutesRemovedToClients(clients, removedRoutes);
+                    notifyRoutesRemovedToManagers(managers, removedRoutes);
                 }
                 if (changedRoutes.size() > 0) {
                     notifyRoutesChangedToClients(clients, changedRoutes);
+                    notifyRoutesChangedToManagers(managers, changedRoutes);
                 }
             }
-            scheduleUpdateProviderInfos();
         }
 
         private int getProviderInfoIndex(String providerId) {
@@ -831,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());
                 }
             }
         }
@@ -874,33 +995,6 @@
             }
         }
 
-        private void scheduleUpdateProviderInfos() {
-            if (!mProviderInfosUpdateScheduled) {
-                mProviderInfosUpdateScheduled = true;
-                sendMessage(PooledLambda.obtainMessage(UserHandler::updateProviderInfos, this));
-            }
-        }
-
-        //TODO: should be replaced into notifyRoutes...ToManagers
-        private void updateProviderInfos() {
-            mProviderInfosUpdateScheduled = false;
-
-            MediaRouter2ServiceImpl service = mServiceRef.get();
-            if (service == null) {
-                return;
-            }
-
-            final List<IMediaRouter2Manager> managers = new ArrayList<>();
-            synchronized (service.mLock) {
-                for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
-                    managers.add(managerRecord.mManager);
-                }
-            }
-            for (IMediaRouter2Manager manager : managers) {
-                notifyProviderInfosUpdatedToManager(manager);
-            }
-        }
-
         private List<IMediaRouter2Client> getClients() {
             final List<IMediaRouter2Client> clients = new ArrayList<>();
             MediaRouter2ServiceImpl service = mServiceRef.get();
@@ -917,6 +1011,20 @@
             return clients;
         }
 
+        private List<IMediaRouter2Manager> getManagers() {
+            final List<IMediaRouter2Manager> managers = new ArrayList<>();
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return managers;
+            }
+            synchronized (service.mLock) {
+                for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
+                    managers.add(managerRecord.mManager);
+                }
+            }
+            return managers;
+        }
+
         private void notifyRoutesToClient(IMediaRouter2Client client) {
             List<MediaRoute2Info> routes = new ArrayList<>();
             for (MediaRoute2ProviderInfo providerInfo : mProviderInfos) {
@@ -932,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) {
@@ -965,11 +1082,51 @@
             }
         }
 
-        private void notifyProviderInfosUpdatedToManager(IMediaRouter2Manager manager) {
+        private void notifyRoutesToManager(IMediaRouter2Manager manager) {
+            List<MediaRoute2Info> routes = new ArrayList<>();
+            for (MediaRoute2ProviderInfo providerInfo : mProviderInfos) {
+                routes.addAll(providerInfo.getRoutes());
+            }
+            if (routes.size() == 0) {
+                return;
+            }
             try {
-                manager.notifyProviderInfosUpdated(mProviderInfos);
+                manager.notifyRoutesAdded(routes);
             } catch (RemoteException ex) {
-                Slog.w(TAG, "Failed to notify provider infos updated. Manager probably died.");
+                Slog.w(TAG, "Failed to notify all routes. Manager probably died.", ex);
+            }
+        }
+
+        private void notifyRoutesAddedToManagers(List<IMediaRouter2Manager> managers,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Manager manager : managers) {
+                try {
+                    manager.notifyRoutesAdded(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes added. Manager probably died.", ex);
+                }
+            }
+        }
+
+        private void notifyRoutesRemovedToManagers(List<IMediaRouter2Manager> managers,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Manager manager : managers) {
+                try {
+                    manager.notifyRoutesRemoved(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes removed. Manager probably died.", ex);
+                }
+            }
+        }
+
+        private void notifyRoutesChangedToManagers(List<IMediaRouter2Manager> managers,
+                List<MediaRoute2Info> routes) {
+            for (IMediaRouter2Manager manager : managers) {
+                try {
+                    manager.notifyRoutesChanged(routes);
+                } catch (RemoteException ex) {
+                    Slog.w(TAG, "Failed to notify routes changed. Manager probably died.", ex);
+                }
             }
         }
 
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/notification/NotificationHistoryDatabase.java b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
index 99b1ef4..f05b2bf 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryDatabase.java
@@ -16,8 +16,15 @@
 
 package com.android.server.notification;
 
+import android.app.AlarmManager;
 import android.app.NotificationHistory;
 import android.app.NotificationHistory.HistoricalNotification;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
 import android.os.Handler;
 import android.util.AtomicFile;
 import android.util.Slog;
@@ -33,11 +40,15 @@
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provides an interface to write and query for notification history data for a user from a Protocol
@@ -52,32 +63,48 @@
     private static final String TAG = "NotiHistoryDatabase";
     private static final boolean DEBUG = NotificationManagerService.DBG;
     private static final int HISTORY_RETENTION_DAYS = 2;
+    private static final int HISTORY_RETENTION_MS = 24 * 60 * 60 * 1000;
     private static final long WRITE_BUFFER_INTERVAL_MS = 1000 * 60 * 20;
 
+    private static final String ACTION_HISTORY_DELETION =
+            NotificationHistoryDatabase.class.getSimpleName() + ".CLEANUP";
+    private static final int REQUEST_CODE_DELETION = 1;
+    private static final String SCHEME_DELETION = "delete";
+    private static final String EXTRA_KEY = "key";
+
+    private final Context mContext;
+    private final AlarmManager mAlarmManager;
     private final Object mLock = new Object();
     private Handler mFileWriteHandler;
     @VisibleForTesting
     // List of files holding history information, sorted newest to oldest
     final LinkedList<AtomicFile> mHistoryFiles;
-    private final GregorianCalendar mCal;
     private final File mHistoryDir;
     private final File mVersionFile;
     // Current version of the database files schema
     private int mCurrentVersion;
     private final WriteBufferRunnable mWriteBufferRunnable;
+    private final FileAttrProvider mFileAttrProvider;
 
     // Object containing posted notifications that have not yet been written to disk
     @VisibleForTesting
     NotificationHistory mBuffer;
 
-    public NotificationHistoryDatabase(File dir) {
+    public NotificationHistoryDatabase(Context context, File dir,
+            FileAttrProvider fileAttrProvider) {
+        mContext = context;
+        mAlarmManager = context.getSystemService(AlarmManager.class);
         mCurrentVersion = DEFAULT_CURRENT_VERSION;
         mVersionFile = new File(dir, "version");
         mHistoryDir = new File(dir, "history");
         mHistoryFiles = new LinkedList<>();
-        mCal = new GregorianCalendar();
         mBuffer = new NotificationHistory();
         mWriteBufferRunnable = new WriteBufferRunnable();
+        mFileAttrProvider = fileAttrProvider;
+
+        IntentFilter deletionFilter = new IntentFilter(ACTION_HISTORY_DELETION);
+        deletionFilter.addDataScheme(SCHEME_DELETION);
+        mContext.registerReceiver(mFileCleaupReceiver, deletionFilter);
     }
 
     public void init(Handler fileWriteHandler) {
@@ -105,7 +132,8 @@
         }
 
         // Sort with newest files first
-        Arrays.sort(files, (lhs, rhs) -> Long.compare(rhs.lastModified(), lhs.lastModified()));
+        Arrays.sort(files, (lhs, rhs) -> Long.compare(mFileAttrProvider.getCreationTime(rhs),
+                mFileAttrProvider.getCreationTime(lhs)));
 
         for (File file : files) {
             mHistoryFiles.addLast(new AtomicFile(file));
@@ -197,31 +225,48 @@
     }
 
     /**
-     * Remove any files that are too old.
+     * Remove any files that are too old and schedule jobs to clean up the rest
      */
     public void prune(final int retentionDays, final long currentTimeMillis) {
         synchronized (mLock) {
-            mCal.setTimeInMillis(currentTimeMillis);
-            mCal.add(Calendar.DATE, -1 * retentionDays);
+            GregorianCalendar retentionBoundary = new GregorianCalendar();
+            retentionBoundary.setTimeInMillis(currentTimeMillis);
+            retentionBoundary.add(Calendar.DATE, -1 * retentionDays);
 
-            while (!mHistoryFiles.isEmpty()) {
-                final AtomicFile currentOldestFile = mHistoryFiles.getLast();
-                final long age = currentTimeMillis
-                        - currentOldestFile.getBaseFile().lastModified();
-                if (age > mCal.getTimeInMillis()) {
+            for (int i = mHistoryFiles.size() - 1; i >= 0; i--) {
+                final AtomicFile currentOldestFile = mHistoryFiles.get(i);
+                final long creationTime =
+                        mFileAttrProvider.getCreationTime(currentOldestFile.getBaseFile());
+                if (creationTime <= retentionBoundary.getTimeInMillis()) {
                     if (DEBUG) {
                         Slog.d(TAG, "Removed " + currentOldestFile.getBaseFile().getName());
                     }
                     currentOldestFile.delete();
                     mHistoryFiles.removeLast();
                 } else {
-                    // all remaining files are newer than the cut off
-                    return;
+                    // all remaining files are newer than the cut off; schedule jobs to delete
+                    final long deletionTime = creationTime + (retentionDays * HISTORY_RETENTION_MS);
+                    scheduleDeletion(currentOldestFile.getBaseFile(), deletionTime);
                 }
             }
         }
     }
 
+    void scheduleDeletion(File file, long deletionTime) {
+        if (DEBUG) {
+            Slog.d(TAG, "Scheduling deletion for " + file.getName() + " at " + deletionTime);
+        }
+        final PendingIntent pi = PendingIntent.getBroadcast(mContext,
+                REQUEST_CODE_DELETION,
+                new Intent(ACTION_HISTORY_DELETION)
+                        .setData(new Uri.Builder().scheme(SCHEME_DELETION)
+                                .appendPath(file.getAbsolutePath()).build())
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                        .putExtra(EXTRA_KEY, file.getAbsolutePath()),
+                PendingIntent.FLAG_UPDATE_CURRENT);
+        mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, deletionTime, pi);
+    }
+
     private void writeLocked(AtomicFile file, NotificationHistory notifications)
             throws IOException {
         FileOutputStream fos = file.startWrite();
@@ -245,6 +290,25 @@
         }
     }
 
+    private final BroadcastReceiver mFileCleaupReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action == null) {
+                return;
+            }
+            if (ACTION_HISTORY_DELETION.equals(action)) {
+                try {
+                    final String filePath = intent.getStringExtra(EXTRA_KEY);
+                    AtomicFile fileToDelete = new AtomicFile(new File(filePath));
+                    fileToDelete.delete();
+                } catch (Exception e) {
+                    Slog.e(TAG, "Failed to delete notification history file", e);
+                }
+            }
+        }
+    };
+
     private final class WriteBufferRunnable implements Runnable {
         @Override
         public void run() {
@@ -277,10 +341,7 @@
                 // Remove packageName entries from pending history
                 mBuffer.removeNotificationsFromWrite(mPkg);
 
-                // Remove packageName entries from files on disk, and rewrite them to disk
-                // Since we sort by modified date, we have to update the files oldest to newest to
-                // maintain the original ordering
-                Iterator<AtomicFile> historyFileItr = mHistoryFiles.descendingIterator();
+                Iterator<AtomicFile> historyFileItr = mHistoryFiles.iterator();
                 while (historyFileItr.hasNext()) {
                     final AtomicFile af = historyFileItr.next();
                     try {
@@ -297,4 +358,24 @@
             }
         }
     }
+
+    public static final class NotificationHistoryFileAttrProvider implements
+            NotificationHistoryDatabase.FileAttrProvider {
+        final static String TAG = "NotifHistoryFileDate";
+
+        public long getCreationTime(File file) {
+            try {
+                BasicFileAttributes attr = Files.readAttributes(FileSystems.getDefault().getPath(
+                        file.getAbsolutePath()), BasicFileAttributes.class);
+                return attr.creationTime().to(TimeUnit.MILLISECONDS);
+            } catch (Exception e) {
+                Slog.w(TAG, "Cannot read creation data for file; using file name");
+                return Long.valueOf(file.getName());
+            }
+        }
+    }
+
+    interface FileAttrProvider {
+        long getCreationTime(File file);
+    }
 }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 887dbb3..cbbf2a0 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -22,6 +22,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
@@ -125,7 +126,7 @@
 
     // pkg|uid => PackagePreferences
     private final ArrayMap<String, PackagePreferences> mPackagePreferences = new ArrayMap<>();
-    // pkg => PackagePreferences
+    // pkg|userId => PackagePreferences
     private final ArrayMap<String, PackagePreferences> mRestoredWithoutUids = new ArrayMap<>();
 
     private final Context mContext;
@@ -172,9 +173,6 @@
         String tag = parser.getName();
         if (!TAG_RANKING.equals(tag)) return;
         synchronized (mPackagePreferences) {
-            // Clobber groups and channels with the xml, but don't delete other data that wasn't
-            // present at the time of serialization.
-            mRestoredWithoutUids.clear();
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 tag = parser.getName();
                 if (type == XmlPullParser.END_TAG && TAG_RANKING.equals(tag)) {
@@ -200,7 +198,8 @@
                             }
                             boolean skipWarningLogged = false;
 
-                            PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
+                            PackagePreferences r = getOrCreatePackagePreferencesLocked(
+                                    name, userId, uid,
                                     XmlUtils.readIntAttribute(
                                             parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
                                     XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -311,17 +310,27 @@
         return mPackagePreferences.get(key);
     }
 
-    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
-        return getOrCreatePackagePreferencesLocked(pkg, uid,
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+            int uid) {
+        return getOrCreatePackagePreferencesLocked(pkg, UserHandle.getUserId(uid), uid,
                 DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
                 DEFAULT_ALLOW_BUBBLE);
     }
 
-    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,
-            int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+            @UserIdInt int userId, int uid) {
+        return getOrCreatePackagePreferencesLocked(pkg, userId, uid,
+                DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
+                DEFAULT_ALLOW_BUBBLE);
+    }
+
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg,
+            @UserIdInt int userId, int uid, int importance, int priority, int visibility,
+            boolean showBadge, boolean allowBubble) {
         final String key = packagePreferencesKey(pkg, uid);
         PackagePreferences
-                r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+                r = (uid == UNKNOWN_UID)
+                ? mRestoredWithoutUids.get(unrestoredPackageKey(pkg, userId))
                 : mPackagePreferences.get(key);
         if (r == null) {
             r = new PackagePreferences();
@@ -340,7 +349,7 @@
             }
 
             if (r.uid == UNKNOWN_UID) {
-                mRestoredWithoutUids.put(pkg, r);
+                mRestoredWithoutUids.put(unrestoredPackageKey(pkg, userId), r);
             } else {
                 mPackagePreferences.put(key, r);
             }
@@ -382,6 +391,10 @@
 
     private boolean createDefaultChannelIfNeededLocked(PackagePreferences r) throws
             PackageManager.NameNotFoundException {
+        if (r.uid == UNKNOWN_UID) {
+            return false;
+        }
+
         if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString(
                     com.android.internal.R.string.default_notification_channel_label));
@@ -744,7 +757,7 @@
             clearLockedFieldsLocked(channel);
             channel.setImportanceLockedByOEM(r.oemLockedImportance);
             if (!channel.isImportanceLockedByOEM()) {
-                if (r.futureOemLockedChannels.remove(channel.getId())) {
+                if (r.oemLockedChannels.contains(channel.getId())) {
                     channel.setImportanceLockedByOEM(true);
                 }
             }
@@ -939,11 +952,10 @@
                                     NotificationChannel channel = r.channels.get(channelId);
                                     if (channel != null) {
                                         channel.setImportanceLockedByOEM(true);
-                                    } else {
-                                        // if this channel shows up in the future, make sure it'll
-                                        // be locked immediately
-                                        r.futureOemLockedChannels.add(channelId);
                                     }
+                                    // Also store the locked channels on the record, so they aren't
+                                    // temporarily lost when data is cleared on the package
+                                    r.oemLockedChannels.add(channelId);
                                 }
                             }
                         }
@@ -1515,9 +1527,9 @@
                     pw.print(" oemLocked=");
                     pw.print(r.oemLockedImportance);
                 }
-                if (!r.futureOemLockedChannels.isEmpty()) {
+                if (!r.oemLockedChannels.isEmpty()) {
                     pw.print(" futureLockedChannels=");
-                    pw.print(r.futureOemLockedChannels);
+                    pw.print(r.oemLockedChannels);
                 }
                 pw.println();
                 for (NotificationChannel channel : r.channels.values()) {
@@ -1769,17 +1781,18 @@
                 synchronized (mPackagePreferences) {
                     mPackagePreferences.remove(packagePreferencesKey(pkg, uid));
                 }
-                mRestoredWithoutUids.remove(pkg);
+                mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
                 updated = true;
             }
         } else {
             for (String pkg : pkgList) {
                 // Package install
-                final PackagePreferences r = mRestoredWithoutUids.get(pkg);
+                final PackagePreferences r =
+                        mRestoredWithoutUids.get(unrestoredPackageKey(pkg, changeUserId));
                 if (r != null) {
                     try {
                         r.uid = mPm.getPackageUidAsUser(r.pkg, changeUserId);
-                        mRestoredWithoutUids.remove(pkg);
+                        mRestoredWithoutUids.remove(unrestoredPackageKey(pkg, changeUserId));
                         synchronized (mPackagePreferences) {
                             mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
                         }
@@ -1910,6 +1923,10 @@
         return pkg + "|" + uid;
     }
 
+    private static String unrestoredPackageKey(String pkg, @UserIdInt int userId) {
+        return pkg + "|" + userId;
+    }
+
     private static class PackagePreferences {
         String pkg;
         int uid = UNKNOWN_UID;
@@ -1922,7 +1939,7 @@
         // these fields are loaded on boot from a different source of truth and so are not
         // written to notification policy xml
         boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
-        List<String> futureOemLockedChannels = new ArrayList<>();
+        List<String> oemLockedChannels = new ArrayList<>();
         boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
 
         Delegate delegate = null;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 12e8069..fc87acb 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -286,7 +286,7 @@
                                 new File(
                                 Environment.getApexDirectory() + File.separator
                                         + apexInfo.moduleName),
-                                new File(apexInfo.modulePath))).collect(
+                                new File(apexInfo.preinstalledModulePath))).collect(
                                 Collectors.toList());
             } catch (RemoteException e) {
                 Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 5195a52..bb5b04a 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -18,6 +18,7 @@
 
 import static android.content.pm.PackageParser.Component;
 import static android.content.pm.PackageParser.IntentInfo;
+import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
 
 import android.Manifest;
@@ -32,6 +33,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.Trace;
 import android.permission.IPermissionManager;
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
@@ -152,13 +154,23 @@
 
         @Override
         public boolean isGloballyEnabled() {
-            return mFeatureEnabled;
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "isGloballyEnabled");
+            try {
+                return mFeatureEnabled;
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
         }
 
         @Override
         public boolean packageIsEnabled(PackageParser.Package pkg) {
-            return mInjector.getCompatibility().isChangeEnabled(
-                    PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled");
+            try {
+                return mInjector.getCompatibility().isChangeEnabled(
+                        PackageManager.FILTER_APPLICATION_QUERY, pkg.applicationInfo);
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
         }
     }
 
@@ -292,42 +304,48 @@
      */
     public void addPackage(PackageParser.Package newPkg,
             Map<String, PackageParser.Package> existing) {
-        // let's re-evaluate the ability of already added packages to see this new package
-        if (newPkg.mForceQueryable
-                || (mSystemAppsQueryable && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
-            mForceQueryable.add(newPkg.packageName);
-        } else {
-            for (String packageName : mQueriesViaIntent.keySet()) {
-                if (packageName == newPkg.packageName) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage");
+        try {
+            // let's re-evaluate the ability of already added packages to see this new package
+            if (newPkg.mForceQueryable
+                    || (mSystemAppsQueryable && (newPkg.isSystem()
+                    || newPkg.isUpdatedSystemApp()))) {
+                mForceQueryable.add(newPkg.packageName);
+            } else {
+                for (String packageName : mQueriesViaIntent.keySet()) {
+                    if (packageName == newPkg.packageName) {
+                        continue;
+                    }
+                    final PackageParser.Package existingPackage = existing.get(packageName);
+                    if (canQuery(existingPackage, newPkg)) {
+                        mQueriesViaIntent.get(packageName).add(newPkg.packageName);
+                    }
+                }
+            }
+            // if the new package declares them, let's evaluate its ability to see existing packages
+            mQueriesViaIntent.put(newPkg.packageName, new HashSet<>());
+            for (PackageParser.Package existingPackage : existing.values()) {
+                if (existingPackage.packageName == newPkg.packageName) {
                     continue;
                 }
-                final PackageParser.Package existingPackage = existing.get(packageName);
-                if (canQuery(existingPackage, newPkg)) {
-                    mQueriesViaIntent.get(packageName).add(newPkg.packageName);
+                if (existingPackage.mForceQueryable
+                        || (mSystemAppsQueryable
+                        && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
+                    continue;
+                }
+                if (canQuery(newPkg, existingPackage)) {
+                    mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName);
                 }
             }
-        }
-        // if the new package declares them, let's evaluate its ability to see existing packages
-        mQueriesViaIntent.put(newPkg.packageName, new HashSet<>());
-        for (PackageParser.Package existingPackage : existing.values()) {
-            if (existingPackage.packageName == newPkg.packageName) {
-                continue;
+            final HashSet<String> queriesPackages = new HashSet<>(
+                    newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size());
+            if (newPkg.mQueriesPackages != null) {
+                queriesPackages.addAll(newPkg.mQueriesPackages);
             }
-            if (existingPackage.mForceQueryable
-                    || (mSystemAppsQueryable
-                    && (newPkg.isSystem() || newPkg.isUpdatedSystemApp()))) {
-                continue;
-            }
-            if (canQuery(newPkg, existingPackage)) {
-                mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName);
-            }
+            mQueriesViaPackage.put(newPkg.packageName, queriesPackages);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-        final HashSet<String> queriesPackages = new HashSet<>(
-                newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size());
-        if (newPkg.mQueriesPackages != null) {
-            queriesPackages.addAll(newPkg.mQueriesPackages);
-        }
-        mQueriesViaPackage.put(newPkg.packageName, queriesPackages);
     }
 
     /**
@@ -365,151 +383,195 @@
      */
     public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting,
             PackageSetting targetPkgSetting, int userId) {
-        final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
-        if (!featureEnabled) {
-            if (DEBUG_LOGGING) {
-                Slog.d(TAG, "filtering disabled; skipped");
-            }
-            return false;
-        }
-        if (callingUid < Process.FIRST_APPLICATION_UID) {
-            if (DEBUG_LOGGING) {
-                Slog.d(TAG, "filtering skipped; " + callingUid + " is system");
-            }
-            return false;
-        }
-        if (callingSetting == null) {
-            Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
-            return true;
-        }
-        PackageSetting callingPkgSetting = null;
-        if (callingSetting instanceof PackageSetting) {
-            callingPkgSetting = (PackageSetting) callingSetting;
-            if (!shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting,
-                    userId)) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
+        try {
+            final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
+            if (!featureEnabled) {
+                if (DEBUG_LOGGING) {
+                    Slog.d(TAG, "filtering disabled; skipped");
+                }
                 return false;
             }
-        } else if (callingSetting instanceof SharedUserSetting) {
-            final ArraySet<PackageSetting> packageSettings =
-                    ((SharedUserSetting) callingSetting).packages;
-            if (packageSettings != null && packageSettings.size() > 0) {
-                for (int i = 0, max = packageSettings.size(); i < max; i++) {
-                    final PackageSetting packageSetting = packageSettings.valueAt(i);
-                    if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting,
-                            userId)) {
-                        return false;
-                    }
-                    if (callingPkgSetting == null && packageSetting.pkg != null) {
-                        callingPkgSetting = packageSetting;
-                    }
+            if (callingUid < Process.FIRST_APPLICATION_UID) {
+                if (DEBUG_LOGGING) {
+                    Slog.d(TAG, "filtering skipped; " + callingUid + " is system");
                 }
-                if (callingPkgSetting == null) {
-                    Slog.wtf(TAG, callingSetting + " does not have any non-null packages!");
-                    return true;
-                }
-            } else {
-                Slog.wtf(TAG, callingSetting + " has no packages!");
+                return false;
+            }
+            if (callingSetting == null) {
+                Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
                 return true;
             }
-        }
+            PackageSetting callingPkgSetting = null;
+            if (callingSetting instanceof PackageSetting) {
+                callingPkgSetting = (PackageSetting) callingSetting;
+                if (!shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting,
+                        userId)) {
+                    return false;
+                }
+            } else if (callingSetting instanceof SharedUserSetting) {
+                final ArraySet<PackageSetting> packageSettings =
+                        ((SharedUserSetting) callingSetting).packages;
+                if (packageSettings != null && packageSettings.size() > 0) {
+                    for (int i = 0, max = packageSettings.size(); i < max; i++) {
+                        final PackageSetting packageSetting = packageSettings.valueAt(i);
+                        if (!shouldFilterApplicationInternal(packageSetting, targetPkgSetting,
+                                userId)) {
+                            return false;
+                        }
+                        if (callingPkgSetting == null && packageSetting.pkg != null) {
+                            callingPkgSetting = packageSetting;
+                        }
+                    }
+                    if (callingPkgSetting == null) {
+                        Slog.wtf(TAG, callingSetting + " does not have any non-null packages!");
+                        return true;
+                    }
+                } else {
+                    Slog.wtf(TAG, callingSetting + " has no packages!");
+                    return true;
+                }
+            }
 
-        if (DEBUG_LOGGING) {
-            log(callingPkgSetting, targetPkgSetting,
-                    DEBUG_ALLOW_ALL ? "ALLOWED" : "BLOCKED");
+            if (DEBUG_LOGGING) {
+                log(callingPkgSetting, targetPkgSetting,
+                        DEBUG_ALLOW_ALL ? "ALLOWED" : "BLOCKED");
+            }
+            return !DEBUG_ALLOW_ALL;
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-        return !DEBUG_ALLOW_ALL;
     }
 
     private boolean shouldFilterApplicationInternal(
             PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId) {
-        final String callingName = callingPkgSetting.pkg.packageName;
-        final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+        return shouldFilterApplicationInternal(callingPkgSetting, targetPkgSetting, userId,
+                true /*expandSharedUser*/);
+    }
 
-        if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "DISABLED");
-            }
-            return false;
-        }
-        // This package isn't technically installed and won't be written to settings, so we can
-        // treat it as filtered until it's available again.
-        if (targetPkg == null) {
-            if (DEBUG_LOGGING) {
-                Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
-            }
-            return true;
-        }
-        final String targetName = targetPkg.packageName;
-        if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "caller pre-R");
-            }
-            return false;
-        }
-        if (isImplicitlyQueryableSystemApp(targetPkgSetting)) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "implicitly queryable sys");
-            }
-            return false;
-        }
-        if (targetPkg.mForceQueryable) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "manifest forceQueryable");
-            }
-            return false;
-        }
-        if (mForceQueryable.contains(targetName)) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "whitelist forceQueryable");
-            }
-            return false;
-        }
-        if (mQueriesViaPackage.containsKey(callingName)
-                && mQueriesViaPackage.get(callingName).contains(
-                targetName)) {
-            // the calling package has explicitly declared the target package; allow
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "queries package");
-            }
-            return false;
-        } else if (mQueriesViaIntent.containsKey(callingName)
-                && mQueriesViaIntent.get(callingName).contains(targetName)) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "queries intent");
-            }
-            return false;
-        }
-        if (mImplicitlyQueryable.get(userId) != null
-                && mImplicitlyQueryable.get(userId).containsKey(callingName)
-                && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
-            if (DEBUG_LOGGING) {
-                log(callingPkgSetting, targetPkgSetting, "implicitly queryable for user");
-            }
-            return false;
-        }
-        if (callingPkgSetting.pkg.instrumentation.size() > 0) {
-            for (int i = 0, max = callingPkgSetting.pkg.instrumentation.size(); i < max; i++) {
-                if (callingPkgSetting.pkg.instrumentation.get(i).info.targetPackage == targetName) {
-                    if (DEBUG_LOGGING) {
-                        log(callingPkgSetting, targetPkgSetting, "instrumentation");
-                    }
-                    return false;
-                }
-            }
-        }
+    /**
+     * @param expandSharedUser true if all members of the shared user a target may belong to should
+     *                         be considered
+     */
+    private boolean shouldFilterApplicationInternal(
+            PackageSetting callingPkgSetting, PackageSetting targetPkgSetting, int userId,
+            boolean expandSharedUser) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
         try {
-            if (mPermissionManager.checkPermission(
-                    Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
-                    == PackageManager.PERMISSION_GRANTED) {
+            // special case shared user targets
+            if (expandSharedUser && targetPkgSetting.sharedUser != null) {
+                for (PackageSetting sharedMemberSetting : targetPkgSetting.sharedUser.packages) {
+                    if (!shouldFilterApplicationInternal(
+                            callingPkgSetting, sharedMemberSetting, userId,
+                            false /*expandSharedUser*/)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            final String callingName = callingPkgSetting.pkg.packageName;
+            final PackageParser.Package targetPkg = targetPkgSetting.pkg;
+
+            if (!mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) {
                 if (DEBUG_LOGGING) {
-                    log(callingPkgSetting, targetPkgSetting, "permission");
+                    log(callingPkgSetting, targetPkgSetting, "DISABLED");
                 }
                 return false;
             }
-        } catch (RemoteException e) {
+            // This package isn't technically installed and won't be written to settings, so we can
+            // treat it as filtered until it's available again.
+            if (targetPkg == null) {
+                if (DEBUG_LOGGING) {
+                    Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
+                }
+                return true;
+            }
+            final String targetName = targetPkg.packageName;
+            if (callingPkgSetting.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.R) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "caller pre-R");
+                }
+                return false;
+            }
+            if (callingPkgSetting.appId == targetPkgSetting.appId) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "same app id");
+                }
+                return false;
+            }
+            if (isImplicitlyQueryableSystemApp(targetPkgSetting)) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "implicitly queryable sys");
+                }
+                return false;
+            }
+            if (targetPkg.mForceQueryable) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "manifest forceQueryable");
+                }
+                return false;
+            }
+            if (mForceQueryable.contains(targetName)) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "whitelist forceQueryable");
+                }
+                return false;
+            }
+            if (mQueriesViaPackage.containsKey(callingName)
+                    && mQueriesViaPackage.get(callingName).contains(
+                    targetName)) {
+                // the calling package has explicitly declared the target package; allow
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "queries package");
+                }
+                return false;
+            } else if (mQueriesViaIntent.containsKey(callingName)
+                    && mQueriesViaIntent.get(callingName).contains(targetName)) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "queries intent");
+                }
+                return false;
+            }
+            if (mImplicitlyQueryable.get(userId) != null
+                    && mImplicitlyQueryable.get(userId).containsKey(callingName)
+                    && mImplicitlyQueryable.get(userId).get(callingName).contains(targetName)) {
+                if (DEBUG_LOGGING) {
+                    log(callingPkgSetting, targetPkgSetting, "implicitly queryable for user");
+                }
+                return false;
+            }
+            final ArrayList<PackageParser.Instrumentation> inst =
+                    callingPkgSetting.pkg.instrumentation;
+            if (inst.size() > 0) {
+                for (int i = 0, max = inst.size(); i < max; i++) {
+                    if (inst.get(i).info.targetPackage == targetName) {
+                        if (DEBUG_LOGGING) {
+                            log(callingPkgSetting, targetPkgSetting, "instrumentation");
+                        }
+                        return false;
+                    }
+                }
+            }
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.checkPermission");
+            try {
+                if (mPermissionManager.checkPermission(
+                        Manifest.permission.QUERY_ALL_PACKAGES, callingName, userId)
+                        == PackageManager.PERMISSION_GRANTED) {
+                    if (DEBUG_LOGGING) {
+                        log(callingPkgSetting, targetPkgSetting, "permission");
+                    }
+                    return false;
+                }
+            } catch (RemoteException e) {
+                return true;
+            } finally {
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
             return true;
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
-        return true;
     }
 
     private static void log(PackageSetting callingPkgSetting, PackageSetting targetPkgSetting,
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..93249e9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -26,7 +26,6 @@
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PackageDeleteObserver;
-import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyEventLogger;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
@@ -512,6 +511,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 +633,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,
@@ -1005,73 +1014,56 @@
         }
     }
 
-    static class PackageInstallObserverAdapter extends PackageInstallObserver {
-        private final Context mContext;
-        private final IntentSender mTarget;
-        private final int mSessionId;
-        private final boolean mShowNotification;
-        private final int mUserId;
-
-        public PackageInstallObserverAdapter(Context context, IntentSender target, int sessionId,
-                boolean showNotification, int userId) {
-            mContext = context;
-            mTarget = target;
-            mSessionId = sessionId;
-            mShowNotification = showNotification;
-            mUserId = userId;
+    static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId,
+            Intent intent) {
+        final Intent fillIn = new Intent();
+        fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+        fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+                PackageInstaller.STATUS_PENDING_USER_ACTION);
+        fillIn.putExtra(Intent.EXTRA_INTENT, intent);
+        try {
+            target.sendIntent(context, 0, fillIn, null, null);
+        } catch (SendIntentException ignored) {
         }
+    }
 
-        @Override
-        public void onUserActionRequired(Intent intent) {
-            final Intent fillIn = new Intent();
-            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageInstaller.STATUS_PENDING_USER_ACTION);
-            fillIn.putExtra(Intent.EXTRA_INTENT, intent);
-            try {
-                mTarget.sendIntent(mContext, 0, fillIn, null, null);
-            } catch (SendIntentException ignored) {
+    static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId,
+            boolean showNotification, int userId, String basePackageName, int returnCode,
+            String msg, Bundle extras) {
+        if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) {
+            boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
+            Notification notification = buildSuccessNotification(context,
+                    context.getResources()
+                            .getString(update ? R.string.package_updated_device_owner :
+                                    R.string.package_installed_device_owner),
+                    basePackageName,
+                    userId);
+            if (notification != null) {
+                NotificationManager notificationManager = (NotificationManager)
+                        context.getSystemService(Context.NOTIFICATION_SERVICE);
+                notificationManager.notify(basePackageName,
+                        SystemMessage.NOTE_PACKAGE_STATE,
+                        notification);
             }
         }
-
-        @Override
-        public void onPackageInstalled(String basePackageName, int returnCode, String msg,
-                Bundle extras) {
-            if (PackageManager.INSTALL_SUCCEEDED == returnCode && mShowNotification) {
-                boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING);
-                Notification notification = buildSuccessNotification(mContext,
-                        mContext.getResources()
-                                .getString(update ? R.string.package_updated_device_owner :
-                                        R.string.package_installed_device_owner),
-                        basePackageName,
-                        mUserId);
-                if (notification != null) {
-                    NotificationManager notificationManager = (NotificationManager)
-                            mContext.getSystemService(Context.NOTIFICATION_SERVICE);
-                    notificationManager.notify(basePackageName,
-                            SystemMessage.NOTE_PACKAGE_STATE,
-                            notification);
-                }
+        final Intent fillIn = new Intent();
+        fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
+        fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+        fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+                PackageManager.installStatusToPublicStatus(returnCode));
+        fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+                PackageManager.installStatusToString(returnCode, msg));
+        fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
+        if (extras != null) {
+            final String existing = extras.getString(
+                    PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
+            if (!TextUtils.isEmpty(existing)) {
+                fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
             }
-            final Intent fillIn = new Intent();
-            fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName);
-            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
-                    PackageManager.installStatusToPublicStatus(returnCode));
-            fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
-                    PackageManager.installStatusToString(returnCode, msg));
-            fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
-            if (extras != null) {
-                final String existing = extras.getString(
-                        PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
-                if (!TextUtils.isEmpty(existing)) {
-                    fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
-                }
-            }
-            try {
-                mTarget.sendIntent(mContext, 0, fillIn, null, null);
-            } catch (SendIntentException ignored) {
-            }
+        }
+        try {
+            target.sendIntent(context, 0, fillIn, null, null);
+        } catch (SendIntentException ignored) {
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index feb1271..d5f4ff2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -18,7 +18,6 @@
 
 import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE;
-import static android.content.pm.PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
 import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
@@ -79,7 +78,6 @@
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelableException;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -107,7 +105,6 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
 import com.android.server.pm.Installer.InstallerException;
-import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
 import com.android.server.pm.dex.DexManager;
 import com.android.server.security.VerityUtils;
 
@@ -131,7 +128,7 @@
 public class PackageInstallerSession extends IPackageInstallerSession.Stub {
     private static final String TAG = "PackageInstallerSession";
     private static final boolean LOGD = true;
-    private static final String REMOVE_SPLIT_MARKER_EXTENSION = ".removed";
+    private static final String REMOVE_MARKER_EXTENSION = ".removed";
 
     private static final int MSG_COMMIT = 1;
     private static final int MSG_ON_PACKAGE_INSTALLED = 2;
@@ -148,6 +145,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";
@@ -259,7 +258,7 @@
     private final ArrayList<FileBridge> mBridges = new ArrayList<>();
 
     @GuardedBy("mLock")
-    private IPackageInstallObserver2 mRemoteObserver;
+    private IntentSender mRemoteStatusReceiver;
 
     /** Fields derived from commit parsing */
     @GuardedBy("mLock")
@@ -296,9 +295,6 @@
     private File mResolvedBaseFile;
 
     @GuardedBy("mLock")
-    private File mResolvedStageDir;
-
-    @GuardedBy("mLock")
     private final List<File> mResolvedStagedFiles = new ArrayList<>();
     @GuardedBy("mLock")
     private final List<File> mResolvedInheritedFiles = new ArrayList<>();
@@ -317,7 +313,7 @@
             // Installers can't stage directories, so it's fine to ignore
             // entries like "lost+found".
             if (file.isDirectory()) return false;
-            if (file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+            if (file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
             if (DexMetadataHelper.isDexMetadataFile(file)) return false;
             if (VerityUtils.isFsveritySignatureFile(file)) return false;
             return true;
@@ -327,7 +323,7 @@
         @Override
         public boolean accept(File file) {
             if (file.isDirectory()) return false;
-            if (!file.getName().endsWith(REMOVE_SPLIT_MARKER_EXTENSION)) return false;
+            if (!file.getName().endsWith(REMOVE_MARKER_EXTENSION)) return false;
             return true;
         }
     };
@@ -344,14 +340,14 @@
                     final String packageName = (String) args.arg1;
                     final String message = (String) args.arg2;
                     final Bundle extras = (Bundle) args.arg3;
-                    final IPackageInstallObserver2 observer = (IPackageInstallObserver2) args.arg4;
+                    final IntentSender statusReceiver = (IntentSender) args.arg4;
                     final int returnCode = args.argi1;
                     args.recycle();
 
-                    try {
-                        observer.onPackageInstalled(packageName, returnCode, message, extras);
-                    } catch (RemoteException ignored) {
-                    }
+                    PackageInstallerService.sendOnPackageInstalled(mContext,
+                            statusReceiver, sessionId,
+                            isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId,
+                            packageName, returnCode, message, extras);
 
                     break;
             }
@@ -562,23 +558,6 @@
         }
     }
 
-    /**
-     * Resolve the actual location where staged data should be written. This
-     * might point at an ASEC mount point, which is why we delay path resolution
-     * until someone actively works with the session.
-     */
-    @GuardedBy("mLock")
-    private File resolveStageDirLocked() throws IOException {
-        if (mResolvedStageDir == null) {
-            if (stageDir != null) {
-                mResolvedStageDir = stageDir;
-            } else {
-                throw new IOException("Missing stageDir");
-            }
-        }
-        return mResolvedStageDir;
-    }
-
     @Override
     public void setClientProgress(float progress) {
         synchronized (mLock) {
@@ -618,14 +597,32 @@
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotCommittedOrDestroyedLocked("getNames");
 
-            try {
-                return resolveStageDirLocked().list();
-            } catch (IOException e) {
-                throw ExceptionUtils.wrap(e);
-            }
+            return getNamesLocked();
         }
     }
 
+    @GuardedBy("mLock")
+    private String[] getNamesLocked() {
+        return stageDir.list();
+    }
+
+    private static File[] filterFiles(File parent, String[] names, FileFilter filter) {
+        return Arrays.stream(names).map(name -> new File(parent, name)).filter(
+                file -> filter.accept(file)).toArray(File[]::new);
+    }
+
+    @GuardedBy("mLock")
+    private File[] getAddedFilesLocked() {
+        String[] names = getNamesLocked();
+        return filterFiles(stageDir, names, sAddedFilter);
+    }
+
+    @GuardedBy("mLock")
+    private File[] getRemovedFilesLocked() {
+        String[] names = getNamesLocked();
+        return filterFiles(stageDir, names, sRemovedFilter);
+    }
+
     @Override
     public void removeSplit(String splitName) {
         if (TextUtils.isEmpty(params.appPackageName)) {
@@ -644,13 +641,17 @@
         }
     }
 
+    private static String getRemoveMarkerName(String name) {
+        final String markerName = name + REMOVE_MARKER_EXTENSION;
+        if (!FileUtils.isValidExtFilename(markerName)) {
+            throw new IllegalArgumentException("Invalid marker: " + markerName);
+        }
+        return markerName;
+    }
+
     private void createRemoveSplitMarkerLocked(String splitName) throws IOException {
         try {
-            final String markerName = splitName + REMOVE_SPLIT_MARKER_EXTENSION;
-            if (!FileUtils.isValidExtFilename(markerName)) {
-                throw new IllegalArgumentException("Invalid marker: " + markerName);
-            }
-            final File target = new File(resolveStageDirLocked(), markerName);
+            final File target = new File(stageDir, getRemoveMarkerName(splitName));
             target.createNewFile();
             Os.chmod(target.getAbsolutePath(), 0 /*mode*/);
         } catch (ErrnoException e) {
@@ -684,7 +685,6 @@
         // will block any attempted install transitions.
         final RevocableFileDescriptor fd;
         final FileBridge bridge;
-        final File stageDir;
         synchronized (mLock) {
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotSealedLocked("openWrite");
@@ -698,8 +698,6 @@
                 bridge = new FileBridge();
                 mBridges.add(bridge);
             }
-
-            stageDir = resolveStageDirLocked();
         }
 
         try {
@@ -805,7 +803,7 @@
             if (!FileUtils.isValidExtFilename(name)) {
                 throw new IllegalArgumentException("Invalid name: " + name);
             }
-            final File target = new File(resolveStageDirLocked(), name);
+            final File target = new File(stageDir, name);
             final FileDescriptor targetFd = Os.open(target.getAbsolutePath(), O_RDONLY, 0);
             return new ParcelFileDescriptor(targetFd);
         } catch (ErrnoException e) {
@@ -951,7 +949,7 @@
      * This method may be called multiple times to update the status receiver validate caller
      * permissions.
      */
-    public boolean markAsCommitted(
+    private boolean markAsCommitted(
             @NonNull IntentSender statusReceiver, boolean forTransfer) {
         Preconditions.checkNotNull(statusReceiver);
 
@@ -962,10 +960,7 @@
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotDestroyedLocked("commit");
 
-            final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
-                    mContext, statusReceiver, sessionId,
-                    isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId);
-            mRemoteObserver = adapter.getBinder();
+            mRemoteStatusReceiver = statusReceiver;
 
             if (forTransfer) {
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
@@ -989,12 +984,7 @@
             if (!mSealed) {
                 try {
                     sealAndValidateLocked(childSessions);
-                } catch (IOException e) {
-                    throw new IllegalArgumentException(e);
                 } catch (PackageManagerException e) {
-                    // Do now throw an exception here to stay compatible with O and older
-                    destroyInternal();
-                    dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
                     return false;
                 }
             }
@@ -1094,52 +1084,59 @@
      */
     @GuardedBy("mLock")
     private void sealAndValidateLocked(List<PackageInstallerSession> childSessions)
-            throws PackageManagerException, IOException {
-        assertNoWriteFileTransfersOpenLocked();
-        assertPreparedAndNotDestroyedLocked("sealing of session");
+            throws PackageManagerException {
+        try {
+            assertNoWriteFileTransfersOpenLocked();
+            assertPreparedAndNotDestroyedLocked("sealing of session");
 
-        mSealed = true;
+            mSealed = true;
 
-        if (childSessions != null) {
-            assertMultiPackageConsistencyLocked(childSessions);
-        }
-
-        if (params.isStaged) {
-            final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
-            final boolean anotherSessionAlreadyInProgress =
-                    activeSession != null && sessionId != activeSession.sessionId
-                            && mParentSessionId != activeSession.sessionId;
-            if (anotherSessionAlreadyInProgress) {
-                throw new PackageManagerException(
-                        PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
-                        "There is already in-progress committed staged session "
-                                + activeSession.sessionId, null);
+            if (childSessions != null) {
+                assertMultiPackageConsistencyLocked(childSessions);
             }
-        }
 
-        // Read transfers from the original owner stay open, but as the session's data
-        // cannot be modified anymore, there is no leak of information. For staged sessions,
-        // further validation is performed by the staging manager.
-        if (!params.isMultiPackage) {
-            final PackageInfo pkgInfo = mPm.getPackageInfo(
-                    params.appPackageName, PackageManager.GET_SIGNATURES
-                            | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
-
-            resolveStageDirLocked();
-
-            try {
-                if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                    validateApexInstallLocked();
-                } else {
-                    validateApkInstallLocked(pkgInfo);
+            if (params.isStaged) {
+                final PackageInstallerSession activeSession = mStagingManager.getActiveSession();
+                final boolean anotherSessionAlreadyInProgress =
+                        activeSession != null && sessionId != activeSession.sessionId
+                                && mParentSessionId != activeSession.sessionId;
+                if (anotherSessionAlreadyInProgress) {
+                    throw new PackageManagerException(
+                            PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
+                            "There is already in-progress committed staged session "
+                                    + activeSession.sessionId, null);
                 }
-            } catch (PackageManagerException e) {
-                throw e;
-            } catch (Throwable e) {
-                // Convert all exceptions into package manager exceptions as only those are handled
-                // in the code above
-                throw new PackageManagerException(e);
             }
+
+            // Read transfers from the original owner stay open, but as the session's data
+            // cannot be modified anymore, there is no leak of information. For staged sessions,
+            // further validation is performed by the staging manager.
+            if (!params.isMultiPackage) {
+                final PackageInfo pkgInfo = mPm.getPackageInfo(
+                        params.appPackageName, PackageManager.GET_SIGNATURES
+                                | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId);
+
+                try {
+                    if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+                        validateApexInstallLocked();
+                    } else {
+                        validateApkInstallLocked(pkgInfo);
+                    }
+                } catch (PackageManagerException e) {
+                    throw e;
+                } catch (Throwable e) {
+                    // Convert all exceptions into package manager exceptions as only those are
+                    // handled in the code above.
+                    throw new PackageManagerException(e);
+                }
+            }
+        } catch (PackageManagerException e) {
+            // Session is sealed but could not be verified, we need to destroy it.
+            destroyInternal();
+            // Dispatch message to remove session from PackageInstallerService
+            dispatchSessionFinished(
+                    e.error, ExceptionUtils.getCompleteMessage(e), null);
+            throw e;
         }
     }
 
@@ -1162,15 +1159,8 @@
         synchronized (mLock) {
             try {
                 sealAndValidateLocked(childSessions);
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
             } catch (PackageManagerException e) {
                 Slog.e(TAG, "Package not valid", e);
-                // Session is sealed but could not be verified, we need to destroy it.
-                destroyInternal();
-                // Dispatch message to remove session from PackageInstallerService
-                dispatchSessionFinished(
-                        e.error, ExceptionUtils.getCompleteMessage(e), null);
             }
         }
     }
@@ -1211,13 +1201,7 @@
 
             try {
                 sealAndValidateLocked(childSessions);
-            } catch (IOException e) {
-                throw new IllegalStateException(e);
             } catch (PackageManagerException e) {
-                // Session is sealed but could not be verified, we need to destroy it
-                destroyInternal();
-                dispatchSessionFinished(e.error, ExceptionUtils.getCompleteMessage(e), null);
-
                 throw new IllegalArgumentException("Package is not valid", e);
             }
 
@@ -1227,7 +1211,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
@@ -1302,11 +1286,10 @@
                 }
             }
             if (!success) {
-                try {
-                    mRemoteObserver.onPackageInstalled(
-                            null, failure.error, failure.getLocalizedMessage(), null);
-                } catch (RemoteException ignored) {
-                }
+                PackageInstallerService.sendOnPackageInstalled(mContext,
+                        mRemoteStatusReceiver, sessionId,
+                        isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
+                        failure.error, failure.getLocalizedMessage(), null);
                 return;
             }
             mPm.installStage(activeChildSessions);
@@ -1350,10 +1333,9 @@
                     final Intent intent = new Intent(PackageInstaller.ACTION_CONFIRM_INSTALL);
                     intent.setPackage(mPm.getPackageInstallerPackageName());
                     intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
-                    try {
-                        mRemoteObserver.onUserActionRequired(intent);
-                    } catch (RemoteException ignored) {
-                    }
+
+                    PackageInstallerService.sendOnUserActionRequired(mContext,
+                            mRemoteStatusReceiver, sessionId, intent);
 
                     // Commit was keeping session marked as active until now; release
                     // that extra refcount so session appears idle.
@@ -1366,7 +1348,7 @@
                 if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
                     try {
                         final List<File> fromFiles = mResolvedInheritedFiles;
-                        final File toDir = resolveStageDirLocked();
+                        final File toDir = stageDir;
 
                         if (LOGD) Slog.d(TAG, "Inherited files: " + mResolvedInheritedFiles);
                         if (!mResolvedInheritedFiles.isEmpty() && mInheritedFilesBase == null) {
@@ -1416,8 +1398,7 @@
                 computeProgressLocked(true);
 
                 // Unpack native libraries
-                extractNativeLibraries(mResolvedStageDir, params.abiOverride,
-                        mayInheritNativeLibs());
+                extractNativeLibraries(stageDir, params.abiOverride, mayInheritNativeLibs());
             }
 
             // We've reached point of no return; call into PMS to install the stage.
@@ -1477,7 +1458,7 @@
     @GuardedBy("mLock")
     private void validateApexInstallLocked()
             throws PackageManagerException {
-        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+        final File[] addedFiles = getAddedFilesLocked();
         if (ArrayUtils.isEmpty(addedFiles)) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
         }
@@ -1487,13 +1468,6 @@
                     "Too many files for apex install");
         }
 
-        try {
-            resolveStageDirLocked();
-        } catch (IOException e) {
-            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
-                    "Failed to resolve stage location", e);
-        }
-
         File addedFile = addedFiles[0]; // there is only one file
 
         // Ensure file name has proper suffix
@@ -1506,7 +1480,7 @@
                     "Invalid filename: " + targetName);
         }
 
-        final File targetFile = new File(mResolvedStageDir, targetName);
+        final File targetFile = new File(stageDir, targetName);
         resolveAndStageFile(addedFile, targetFile);
 
         mResolvedBaseFile = targetFile;
@@ -1547,25 +1521,18 @@
                 && params.mode == SessionParams.MODE_INHERIT_EXISTING
                 && VerityUtils.hasFsverity(pkgInfo.applicationInfo.getBaseCodePath());
 
-        try {
-            resolveStageDirLocked();
-        } catch (IOException e) {
-            throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
-                    "Failed to resolve stage location", e);
-        }
-
-        final File[] removedFiles = mResolvedStageDir.listFiles(sRemovedFilter);
+        final File[] removedFiles = getRemovedFilesLocked();
         final List<String> removeSplitList = new ArrayList<>();
         if (!ArrayUtils.isEmpty(removedFiles)) {
             for (File removedFile : removedFiles) {
                 final String fileName = removedFile.getName();
                 final String splitName = fileName.substring(
-                        0, fileName.length() - REMOVE_SPLIT_MARKER_EXTENSION.length());
+                        0, fileName.length() - REMOVE_MARKER_EXTENSION.length());
                 removeSplitList.add(splitName);
             }
         }
 
-        final File[] addedFiles = mResolvedStageDir.listFiles(sAddedFilter);
+        final File[] addedFiles = getAddedFilesLocked();
         if (ArrayUtils.isEmpty(addedFiles) && removeSplitList.size() == 0) {
             throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, "No packages staged");
         }
@@ -1609,7 +1576,7 @@
                         "Invalid filename: " + targetName);
             }
 
-            final File targetFile = new File(mResolvedStageDir, targetName);
+            final File targetFile = new File(stageDir, targetName);
             resolveAndStageFile(addedFile, targetFile);
 
             // Base is coming from session
@@ -1624,7 +1591,7 @@
                     throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                             "Invalid filename: " + dexMetadataFile);
                 }
-                final File targetDexMetadataFile = new File(mResolvedStageDir,
+                final File targetDexMetadataFile = new File(stageDir,
                         DexMetadataHelper.buildDexMetadataPathForApk(targetName));
                 resolveAndStageFile(dexMetadataFile, targetDexMetadataFile);
             }
@@ -2184,17 +2151,17 @@
     }
 
     private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
-        final IPackageInstallObserver2 observer;
+        final IntentSender statusReceiver;
         final String packageName;
         synchronized (mLock) {
             mFinalStatus = returnCode;
             mFinalMessage = msg;
 
-            observer = mRemoteObserver;
+            statusReceiver = mRemoteStatusReceiver;
             packageName = mPackageName;
         }
 
-        if (observer != null) {
+        if (statusReceiver != null) {
             // Execute observer.onPackageInstalled on different tread as we don't want callers
             // inside the system server have to worry about catching the callbacks while they are
             // calling into the session
@@ -2202,7 +2169,7 @@
             args.arg1 = packageName;
             args.arg2 = msg;
             args.arg3 = extras;
-            args.arg4 = observer;
+            args.arg4 = statusReceiver;
             args.argi1 = returnCode;
 
             mHandler.obtainMessage(MSG_ON_PACKAGE_INSTALLED, args).sendToTarget();
@@ -2211,8 +2178,10 @@
         final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
 
         // Send broadcast to default launcher only if it's a new install
+        // TODO(b/144270665): Secure the usage of this broadcast.
         final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
-        if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()) {
+        if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
+                && (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
             mPm.sendSessionCommitBroadcast(generateInfo(), userId);
         }
 
@@ -2336,7 +2305,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 +2391,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 +2500,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 +2594,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 cc443cb..525d357 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1159,15 +1159,14 @@
 
         ArrayList<String> inPaths = getRemainingArgs();
         if (inPaths.isEmpty()) {
-            pw.println("Error: must either specify APK files or '-' to read from stdin");
-            return 1;
+            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 '-'");
+                pw.println("Error: can't specify SPLIT(s) along with STDIN");
                 return 1;
             }
             if (params.sessionParams.sizeBytes == -1) {
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/TEST_MAPPING b/services/core/java/com/android/server/pm/TEST_MAPPING
index f7b60c2..e8798ff 100644
--- a/services/core/java/com/android/server/pm/TEST_MAPPING
+++ b/services/core/java/com/android/server/pm/TEST_MAPPING
@@ -22,6 +22,9 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "PackageManagerShellCommandTest"
     }
   ],
   "postsubmit": [
diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
index ef6b24c..4654cca 100644
--- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
+++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java
@@ -389,7 +389,7 @@
         final ArrayMap<String, Integer> result = new ArrayMap<>(whitelist.size() + 1);
         // First, do the whitelisted user types.
         for (int i = 0; i < whitelist.size(); i++) {
-            final String pkgName = whitelist.keyAt(i);
+            final String pkgName = whitelist.keyAt(i).intern();
             final int flags = getFlagsFromUserTypes(whitelist.valueAt(i));
             if (flags != 0) {
                 result.put(pkgName, flags);
@@ -402,7 +402,7 @@
         final ArrayMap<String, Set<String>> blacklist =
                 sysConfig.getAndClearPackageToUserTypeBlacklist();
         for (int i = 0; i < blacklist.size(); i++) {
-            final String pkgName = blacklist.keyAt(i);
+            final String pkgName = blacklist.keyAt(i).intern();
             final int nonFlags = getFlagsFromUserTypes(blacklist.valueAt(i));
             final Integer flags = result.get(pkgName);
             if (flags != null) {
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/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index bb3388c..e9aad4f 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1539,6 +1539,16 @@
             public void onInstallPermissionUpdated() {
                 mDefaultPermissionCallback.onInstallPermissionUpdated();
             }
+
+            public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds,
+                    boolean sync, int uid) {
+                onPermissionUpdated(updatedUserIds, sync);
+                mOnPermissionChangeListeners.onPermissionsChanged(uid);
+            }
+
+            public void onInstallPermissionUpdatedNotifyListener(int uid) {
+                mDefaultPermissionCallback.onInstallPermissionUpdatedNotifyListener(uid);
+            }
         };
 
         for (int i = 0; i < permissionCount; i++) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index a807a7e..fb5c6fdd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -162,12 +162,14 @@
         }
         public void onPermissionUpdatedNotifyListener(@UserIdInt int[] updatedUserIds, boolean sync,
                 int uid) {
+            onPermissionUpdated(updatedUserIds, sync);
         }
         public void onPermissionRemoved() {
         }
         public void onInstallPermissionUpdated() {
         }
         public void onInstallPermissionUpdatedNotifyListener(int uid) {
+            onInstallPermissionUpdated();
         }
     }
 
diff --git a/services/core/java/com/android/server/policy/LegacyGlobalActions.java b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
index bbee393b..c779ebf 100644
--- a/services/core/java/com/android/server/policy/LegacyGlobalActions.java
+++ b/services/core/java/com/android/server/policy/LegacyGlobalActions.java
@@ -16,24 +16,6 @@
 
 package com.android.server.policy;
 
-import com.android.internal.app.AlertController;
-import com.android.internal.globalactions.Action;
-import com.android.internal.globalactions.ActionsAdapter;
-import com.android.internal.globalactions.ActionsDialog;
-import com.android.internal.globalactions.LongPressAction;
-import com.android.internal.globalactions.SinglePressAction;
-import com.android.internal.globalactions.ToggleAction;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.R;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.util.EmergencyAffordanceManager;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.server.policy.PowerAction;
-import com.android.server.policy.RestartAction;
-import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
-
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -57,6 +39,7 @@
 import android.provider.Settings;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
+import android.sysprop.TelephonyProperties;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
@@ -69,6 +52,21 @@
 import android.view.WindowManagerGlobal;
 import android.widget.AdapterView;
 
+import com.android.internal.R;
+import com.android.internal.app.AlertController;
+import com.android.internal.globalactions.Action;
+import com.android.internal.globalactions.ActionsAdapter;
+import com.android.internal.globalactions.ActionsDialog;
+import com.android.internal.globalactions.LongPressAction;
+import com.android.internal.globalactions.SinglePressAction;
+import com.android.internal.globalactions.ToggleAction;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.EmergencyAffordanceManager;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -229,8 +227,7 @@
 
             @Override
             public void onToggle(boolean on) {
-                if (mHasTelephony && Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
+                if (mHasTelephony && TelephonyProperties.in_ecm_mode().orElse(false)) {
                     mIsWaitingForEcmExit = true;
                     // Launch ECM exit dialog
                     Intent ecmDialogIntent =
@@ -247,8 +244,7 @@
                 if (!mHasTelephony) return;
 
                 // In ECM mode airplane state cannot be changed
-                if (!(Boolean.parseBoolean(
-                        SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
+                if (!TelephonyProperties.in_ecm_mode().orElse(false)) {
                     mState = buttonOn ? State.TurningOn : State.TurningOff;
                     mAirplaneState = mState;
                 }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 9b9f93f..3c4e3f6 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -29,8 +29,10 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -169,6 +171,23 @@
         } catch (RemoteException doesNotHappen) {
             Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
         }
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        intentFilter.addDataScheme("package");
+
+        getContext().registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                UserHandle user =
+                        UserHandle.getUserHandleForUid(intent.getIntExtra(Intent.EXTRA_UID, -1));
+                new PermissionControllerManager(
+                        getUserContext(getContext(), user), FgThread.getHandler())
+                        .updateUserSensitive();
+            }
+        }, UserHandle.ALL, intentFilter, null, null);
+
     }
 
     /**
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/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index 28c171b..9347d21 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -32,6 +32,7 @@
 import android.app.timezone.RulesManager;
 import android.app.timezone.RulesState;
 import android.content.Context;
+import android.icu.util.TimeZone;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -45,7 +46,6 @@
 import com.android.timezone.distro.TimeZoneDistro;
 import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
 
-import libcore.icu.ICU;
 import libcore.timezone.TimeZoneDataFiles;
 import libcore.timezone.TimeZoneFinder;
 import libcore.timezone.TzDataSetVersion;
@@ -519,7 +519,7 @@
                             // Report the active rules version (i.e. the rules in use by the current
                             // process).
                             pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): "
-                                    + ICU.getTZDataVersion() + ","
+                                    + TimeZone.getTZDataVersion() + ","
                                     + ZoneInfoDB.getInstance().getVersion() + ","
                                     + TimeZoneFinder.getInstance().getIanaVersion());
                             break;
@@ -535,7 +535,7 @@
 
         pw.println("RulesManagerService state: " + toString());
         pw.println("Active rules version (ICU, ZoneInfoDB, TimeZoneFinder): "
-                + ICU.getTZDataVersion() + ","
+                + TimeZone.getTZDataVersion() + ","
                 + ZoneInfoDB.getInstance().getVersion() + ","
                 + TimeZoneFinder.getInstance().getIanaVersion());
         pw.println("Distro state: " + rulesState.toString());
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 1268113..ebfc65e 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -123,6 +123,9 @@
 
     private boolean mSleeping;
 
+    /** We started the process of removing the display from the system. */
+    private boolean mRemoving;
+
     /**
      * The display is removed from the system and we are just waiting for all activities on it to be
      * finished before removing this object.
@@ -177,6 +180,7 @@
         mDisplayContent.reconfigureDisplayLocked();
         onRequestedOverrideConfigurationChanged(
                 mDisplayContent.getRequestedOverrideConfiguration());
+        mService.mWindowManager.mDisplayNotificationController.dispatchDisplayAdded(this);
     }
 
     void onDisplayChanged() {
@@ -200,23 +204,37 @@
         }
     }
 
+    // TODO(display-unify): Merge with addChild below.
     void addChild(ActivityStack stack, int position) {
+        addChild(stack, position, false /*fromDc*/);
+    }
+
+    void addChild(ActivityStack stack, int position, boolean fromDc) {
+        boolean toTop = position == POSITION_TOP;
         if (position == POSITION_BOTTOM) {
             position = 0;
-        } else if (position == POSITION_TOP) {
-            position = mStacks.size();
+        } else if (toTop) {
+            position = getChildCount();
         }
         if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
                 + " to displayId=" + mDisplayId + " position=" + position);
         addStackReferenceIfNeeded(stack);
+        if (!fromDc) {
+            mDisplayContent.setStackOnDisplay(stack, position);
+        }
         positionChildAt(stack, position);
         mService.updateSleepIfNeededLocked();
     }
 
-    void removeChild(ActivityStack stack) {
+    // TODO(display-unify): Merge with removeChild below.
+    void onChildRemoved(ActivityStack stack) {
+        if (!mStacks.remove(stack)) {
+            // Stack no longer here!
+            return;
+        }
+
         if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
                 + " from displayId=" + mDisplayId);
-        mStacks.remove(stack);
         if (mPreferredTopFocusableStack == stack) {
             mPreferredTopFocusableStack = null;
         }
@@ -226,13 +244,17 @@
         onStackOrderChanged(stack);
     }
 
+    void removeChild(ActivityStack stack) {
+        mDisplayContent.removeStackFromDisplay(stack);
+    }
+
     void positionChildAtTop(ActivityStack stack, boolean includingParents) {
         positionChildAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
     }
 
     void positionChildAtTop(ActivityStack stack, boolean includingParents,
             String updateLastFocusedStackReason) {
-        positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason);
+        positionChildAt(stack, getChildCount(), includingParents, updateLastFocusedStackReason);
     }
 
     void positionChildAtBottom(ActivityStack stack) {
@@ -267,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;
@@ -286,25 +308,21 @@
 
         // Since positionChildAt() is called during the creation process of pinned stacks,
         // ActivityStack#getStack() can be null.
-        if (stack.getTaskStack() != null && mDisplayContent != null) {
-            mDisplayContent.positionStackAt(insertPosition,
-                    stack.getTaskStack(), includingParents);
-        }
-        if (!wasContained) {
-            stack.setParent(this);
+        if (mDisplayContent != null) {
+            mDisplayContent.positionStackAt(insertPosition, stack, includingParents);
         }
         onStackOrderChanged(stack);
     }
 
     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;
@@ -319,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;
             }
@@ -345,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;
             }
@@ -386,7 +404,7 @@
      * @see #getOrCreateStack(int, int, boolean)
      */
     <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
-            @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
+            @Nullable ActivityOptions options, @Nullable Task candidateTask, int activityType,
             boolean onTop) {
         // First preference is the windowing mode in the activity options if set.
         int windowingMode = (options != null)
@@ -472,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;
             }
@@ -487,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;
             }
@@ -543,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;
             }
@@ -570,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
@@ -635,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;
                 }
@@ -663,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);
                 }
@@ -735,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;
                 }
@@ -764,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;
@@ -833,7 +851,7 @@
      * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
      */
     int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable TaskRecord task, int activityType) {
+            @Nullable Task task, int activityType) {
 
         // First preference if the windowing mode in the activity options if set.
         int windowingMode = (options != null)
@@ -864,12 +882,12 @@
      *
      * @param windowingMode The windowing-mode to validate.
      * @param r The {@link ActivityRecord} to check against.
-     * @param task The {@link TaskRecord} to check against.
+     * @param task The {@link Task} to check against.
      * @param activityType An activity type.
      * @return The provided windowingMode or the closest valid mode which is appropriate.
      */
-    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r,
-        @Nullable TaskRecord task, int activityType) {
+    int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r, @Nullable Task task,
+            int activityType) {
         // Make sure the windowing mode we are trying to use makes sense for what is supported.
         boolean supportsMultiWindow = mService.mSupportsMultiWindow;
         boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
@@ -913,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) {
@@ -921,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;
             }
@@ -931,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;
             }
@@ -962,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;
@@ -1095,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();
         }
     }
 
@@ -1148,7 +1166,7 @@
 
     @Override
     public String toString() {
-        return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
+        return "ActivityDisplay={" + mDisplayId + " numStacks=" + getChildCount() + "}";
     }
 
     @Override
@@ -1186,7 +1204,15 @@
         return mRemoved;
     }
 
+    /**
+     * @see #mRemoving
+     */
+    boolean isRemoving() {
+        return mRemoving;
+    }
+
     void remove() {
+        mRemoving = true;
         final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
         ActivityStack lastReparentedStack = null;
         mPreferredTopFocusableStack = null;
@@ -1199,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();
@@ -1213,14 +1239,14 @@
                     final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
                             ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                             : WINDOWING_MODE_UNDEFINED;
-                    stack.reparent(toDisplay, true /* onTop */, true /* displayRemoved */);
+                    stack.reparent(toDisplay.mDisplayContent, true /* onTop */);
                     stack.setWindowingMode(windowingMode);
                     lastReparentedStack = stack;
                 }
                 // Stacks may be removed from this display. Ensure each stack will be processed and
                 // the loop will end.
-                stackNdx -= numStacks - mStacks.size();
-                numStacks = mStacks.size();
+                stackNdx -= numStacks - getChildCount();
+                numStacks = getChildCount();
             }
         } finally {
             mRootActivityContainer.mStackSupervisor.endDeferResume();
@@ -1246,12 +1272,12 @@
             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
             // removal.
-            stack.remove();
+            stack.removeIfPossible();
         } else if (mStacks.isEmpty()) {
             mDisplayContent.removeIfPossible();
             mDisplayContent = null;
@@ -1323,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;
     }
 
     /**
@@ -1340,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;
             }
@@ -1422,9 +1448,9 @@
             return null;
         }
 
-        final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
+        final ArrayList<Task> tasks = mHomeStack.getAllTasks();
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = tasks.get(taskNdx);
+            final Task task = tasks.get(taskNdx);
             if (!task.isActivityTypeHome()) {
                 continue;
             }
@@ -1520,7 +1546,7 @@
     void removeAllTasks() {
         for (int i = getChildCount() - 1; i >= 0; --i) {
             final ActivityStack stack = getChildAt(i);
-            final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            final ArrayList<Task> tasks = stack.getAllTasks();
             for (int j = tasks.size() - 1; j >= 0; --j) {
                 stack.removeChild(tasks.get(j), "removeAllTasks");
             }
@@ -1528,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) {
@@ -1552,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(",");
             }
@@ -1576,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 c506e27..73034b0 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -92,6 +92,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
+
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -171,7 +172,7 @@
             switch (msg.what) {
                 case MSG_CHECK_VISIBILITY:
                     final SomeArgs args = (SomeArgs) msg.obj;
-                    checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
+                    checkVisibility((Task) args.arg1, (ActivityRecord) args.arg2);
                     break;
             }
         }
@@ -536,7 +537,7 @@
         if (info.launchedActivity != activityRecord) {
             return;
         }
-        final TaskRecord t = activityRecord.getTaskRecord();
+        final Task t = activityRecord.getTask();
         final SomeArgs args = SomeArgs.obtain();
         args.arg1 = t;
         args.arg2 = activityRecord;
@@ -544,7 +545,7 @@
     }
 
     /** @return {@code true} if the given task has an activity will be drawn. */
-    private static boolean hasActivityToBeDrawn(TaskRecord t) {
+    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) {
@@ -554,7 +555,7 @@
         return false;
     }
 
-    private void checkVisibility(TaskRecord t, ActivityRecord r) {
+    private void checkVisibility(Task t, ActivityRecord r) {
         synchronized (mSupervisor.mService.mGlobalLock) {
 
             final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
@@ -984,7 +985,7 @@
             }
         } else if (info.startResult == START_SUCCESS
                 || (info.startResult == START_TASK_TO_FRONT)) {
-            // TaskRecord may still exist when cold launching an activity and the start
+            // Task may still exist when cold launching an activity and the start
             // result will be set to START_TASK_TO_FRONT. Treat this as a COLD launch.
             return TYPE_TRANSITION_COLD_LAUNCH;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 8aa5e77..e80c9b3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -44,7 +44,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.app.WindowConfiguration.activityTypeToString;
 import static android.content.Intent.ACTION_MAIN;
 import static android.content.Intent.CATEGORY_HOME;
@@ -417,7 +416,7 @@
     private int logo;               // resource identifier of activity's logo.
     private int theme;              // resource identifier of activity's theme.
     private int windowFlags;        // custom window flags for preview window.
-    private TaskRecord task;        // the task this is in.
+    private Task task;              // the task this is in.
     private long createTime = System.currentTimeMillis();
     long lastVisibleTime;         // last time this activity became visible
     long cpuTimeAtResume;         // the cpu time of host process at the time of resuming activity
@@ -1148,7 +1147,7 @@
         }
     }
 
-    TaskRecord getTaskRecord() {
+    Task getTask() {
         return task;
     }
 
@@ -1156,33 +1155,22 @@
      * Sets the Task on this activity for the purposes of re-use during launch where we will
      * re-use another activity instead of this one for the launch.
      */
-    void setTaskForReuse(TaskRecord task) {
+    void setTaskForReuse(Task task) {
         this.task = task;
     }
 
-    Task getTask() {
-        return (Task) getParent();
-    }
-
-    TaskStack getStack() {
-        final Task task = getTask();
-        if (task != null) {
-            return task.getTaskStack();
-        } else {
-            return null;
-        }
+    ActivityStack getStack() {
+        return task != null ? task.getTaskStack() : null;
     }
 
     @Override
     void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final TaskRecord oldTask = oldParent != null ? (TaskRecord) oldParent : null;
-        final TaskRecord newTask = newParent != null ? (TaskRecord) newParent : null;
+        final Task oldTask = oldParent != null ? (Task) oldParent : null;
+        final Task newTask = newParent != null ? (Task) newParent : null;
         this.task = newTask;
 
         super.onParentChanged(newParent, oldParent);
 
-        final Task task = getTask();
-
         if (oldParent == null && newParent != null) {
             // First time we are adding the activity to the system.
             mVoiceInteraction = newTask.voiceSession != null;
@@ -1213,7 +1201,7 @@
         } else if (mLastParent != null && mLastParent.getTaskStack() != null) {
             task.getTaskStack().mExitingActivities.remove(this);
         }
-        final TaskStack stack = getStack();
+        final ActivityStack stack = getStack();
 
         // If we reparent, make sure to remove ourselves from the old animation registry.
         if (mAnimatingActivityRegistry != null) {
@@ -1277,7 +1265,7 @@
 
         if (prevDc.mFocusedApp == this) {
             prevDc.setFocusedApp(null);
-            final TaskStack stack = dc.getTopStack();
+            final ActivityStack stack = dc.getTopStack();
             if (stack != null) {
                 final Task task = stack.getTopChild();
                 if (task != null && task.getTopChild() == this) {
@@ -1311,7 +1299,7 @@
             // represents this. In fullscreen-mode, the stack does (since the orientation letterbox
             // is also applied to the task).
             Rect spaceToFill = (inMultiWindowMode() || getStack() == null)
-                    ? getTask().getDisplayedBounds() : getStack().getDisplayedBounds();
+                    ? task.getDisplayedBounds() : getStack().getDisplayedBounds();
             mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint);
         } else if (mLetterbox != null) {
             mLetterbox.hide();
@@ -1637,8 +1625,7 @@
         }
 
         final ActivityManager.TaskSnapshot snapshot =
-                mWmService.mTaskSnapshotController.getSnapshot(
-                        getTask().mTaskId, getTask().mUserId,
+                mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId,
                         false /* restoreFromDisk */, false /* reducedResolution */);
         final int type = getStartingWindowType(newTask, taskSwitch, processRunning,
                 allowTaskSnapshot, activityCreated, fromRecents, snapshot);
@@ -1823,7 +1810,7 @@
         if (snapshot == null) {
             return false;
         }
-        return getTask().getConfiguration().orientation == snapshot.getOrientation();
+        return task.getConfiguration().orientation == snapshot.getOrientation();
     }
 
     void removeStartingWindow() {
@@ -1893,12 +1880,12 @@
      * Reparents this activity into {@param newTask} at the provided {@param position}.  The caller
      * should ensure that the {@param newTask} is not already the parent of this activity.
      */
-    void reparent(TaskRecord newTask, int position, String reason) {
+    void reparent(Task newTask, int position, String reason) {
         if (getParent() == null) {
             Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken);
             return;
         }
-        final TaskRecord prevTask = task;
+        final Task prevTask = task;
         if (prevTask == newTask) {
             throw new IllegalArgumentException(reason + ": task=" + newTask
                     + " is already the parent of r=" + this);
@@ -1985,7 +1972,7 @@
         setActivityType(activityType);
     }
 
-    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
+    void setTaskToAffiliateWith(Task taskToAffiliateWith) {
         if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
             task.setTaskToAffiliateWith(taskToAffiliateWith);
         }
@@ -1994,9 +1981,8 @@
     /**
      * @return Stack value from current task, null if there is no task.
      */
-    // TODO(stack-unify): Remove once ActivityStack and TaskStack are unified.
-    <T extends ActivityStack> T getActivityStack() {
-        return task != null ? (T) task.getStack() : null;
+    ActivityStack getActivityStack() {
+        return task != null ? task.getStack() : null;
     }
 
     int getStackId() {
@@ -2082,10 +2068,11 @@
         return ActivityInfo.isResizeableMode(info.resizeMode) || info.supportsPictureInPicture();
     }
 
-    /**
-     * @return whether this activity is non-resizeable or forced to be resizeable
-     */
-    boolean isNonResizableOrForcedResizable() {
+    /** @return whether this activity is non-resizeable or forced to be resizeable */
+    boolean isNonResizableOrForcedResizable(int windowingMode) {
+        if (windowingMode == WINDOWING_MODE_PINNED && info.supportsPictureInPicture()) {
+            return false;
+        }
         return info.resizeMode != RESIZE_MODE_RESIZEABLE
                 && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
     }
@@ -2241,7 +2228,8 @@
                 return false;
             }
         }
-        return getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable();
+        return (getWindowConfiguration().canReceiveKeys() || isAlwaysFocusable())
+                && getParent() != null;
     }
 
     /** Move activity with its stack to front and make the stack focused. */
@@ -2253,7 +2241,6 @@
             return false;
         }
 
-        final TaskRecord task = getTaskRecord();
         final ActivityStack stack = getActivityStack();
         if (stack == null) {
             Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity="
@@ -2282,7 +2269,7 @@
 
     /** Finish all activities in the task with the same affinity as this one. */
     void finishActivityAffinity() {
-        final ArrayList<ActivityRecord> activities = getTaskRecord().mChildren;
+        final ArrayList<ActivityRecord> activities = task.mChildren;
         for (int index = activities.indexOf(this); index >= 0; --index) {
             final ActivityRecord cur = activities.get(index);
             if (!Objects.equals(cur.taskAffinity, taskAffinity)) {
@@ -2390,7 +2377,9 @@
         mAtmService.deferWindowLayout();
         try {
             makeFinishingLocked();
-            final TaskRecord task = getTaskRecord();
+            // Make a local reference to its task since this.task could be set to null once this
+            // activity is destroyed and detached from task.
+            final Task task = getTask();
             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                     mUserId, System.identityHashCode(this),
                     task.mTaskId, shortComponentName, reason);
@@ -2667,16 +2656,18 @@
         }
 
         EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY, mUserId,
-                System.identityHashCode(this), getTaskRecord().mTaskId, shortComponentName, reason);
+                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()) {
@@ -2741,10 +2732,6 @@
 
         configChangeFlags = 0;
 
-        if (!stack.removeActivityFromLRUList(this) && hadApp) {
-            Slog.w(TAG, "Activity " + this + " being finished, but not in LRU list");
-        }
-
         return removedFromHistory;
     }
 
@@ -2870,8 +2857,6 @@
     }
 
     boolean shouldFreezeBounds() {
-        final Task task = getTask();
-
         // For freeform windows, we can't freeze the bounds at the moment because this would make
         // the resizing unresponsive.
         if (task == null || task.inFreeformWindowingMode()) {
@@ -2882,7 +2867,7 @@
         // the divider/drag handle being released, and the handling it's new
         // configuration. If we are relaunched outside of the drag resizing state,
         // we need to be careful not to do this.
-        return getTask().isDragResizing();
+        return task.isDragResizing();
     }
 
     void startRelaunching() {
@@ -2906,7 +2891,6 @@
      * with a queue.
      */
     private void freezeBounds() {
-        final Task task = getTask();
         mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds));
 
         if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) {
@@ -3037,7 +3021,7 @@
             getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token);
         }
 
-        final TaskStack stack = getStack();
+        final ActivityStack stack = getStack();
         if (delayed && !isEmpty()) {
             // set the token aside because it has an active animation to be finished
             ProtoLog.v(WM_DEBUG_ADD_REMOVE,
@@ -3286,7 +3270,6 @@
      * immediately finishes after, so we have to transfer T to M.
      */
     void transferStartingWindowFromHiddenAboveTokenIfNeeded() {
-        final Task task = getTask();
         for (int i = task.mChildren.size() - 1; i >= 0; i--) {
             final ActivityRecord fromActivity = task.mChildren.get(i);
             if (fromActivity == this) {
@@ -3398,7 +3381,6 @@
      */
     @Nullable
     private ActivityRecord getActivityBelow() {
-        final Task task = getTask();
         final int pos = task.mChildren.indexOf(this);
         if (pos == -1) {
             throw new IllegalStateException("Activity not found in its task");
@@ -3474,7 +3456,7 @@
         }
     }
 
-    void logStartActivity(int tag, TaskRecord task) {
+    void logStartActivity(int tag, Task task) {
         final Uri data = intent.getData();
         final String strData = data != null ? data.toSafeString() : null;
 
@@ -3769,7 +3751,7 @@
 
                 // Notify the pinned stack upon all windows drawn. If there was an animation in
                 // progress then this signal will resume that animation.
-                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
+                final ActivityStack pinnedStack = mDisplayContent.getPinnedStack();
                 if (pinnedStack != null) {
                     pinnedStack.onAllWindowsDrawn();
                 }
@@ -4211,10 +4193,8 @@
 
         mState = state;
 
-        final TaskRecord parent = getTaskRecord();
-
-        if (parent != null) {
-            parent.onActivityStateChanged(this, state, reason);
+        if (task != null) {
+            task.onActivityStateChanged(this, state, reason);
         }
 
         // The WindowManager interprets the app stopping signal as
@@ -5337,7 +5317,7 @@
         if (r == null) {
             return INVALID_TASK_ID;
         }
-        final TaskRecord task = r.task;
+        final Task task = r.task;
         final int activityNdx = task.mChildren.indexOf(r);
         if (activityNdx < 0
                 || (onlyRoot && activityNdx > task.findRootIndex(true /* effectiveRoot */))) {
@@ -5631,7 +5611,6 @@
 
     @VisibleForTesting
     boolean shouldAnimate(int transit) {
-        final Task task = getTask();
         if (task != null && !task.shouldAnimate()) {
             return false;
         }
@@ -5647,11 +5626,7 @@
 
     @Override
     boolean isChangingAppTransition() {
-        final Task task = getTask();
-        if (task != null) {
-            return task.isChangingAppTransition();
-        }
-        return super.isChangingAppTransition();
+        return task != null ? task.isChangingAppTransition() : super.isChangingAppTransition();
     }
 
     @Override
@@ -5751,7 +5726,6 @@
             return;
         }
 
-        Task task = getTask();
         if (mThumbnail == null && task != null && !hasCommittedReparentToAnimationLeash()) {
             SurfaceControl.ScreenshotGraphicBuffer snapshot =
                     mWmService.mTaskSnapshotController.createTaskSnapshot(
@@ -5803,12 +5777,11 @@
         // of the pinned stack or animation layer. The leash is then reparented to this new layer.
         if (mNeedsAnimationBoundsLayer) {
             mTmpRect.setEmpty();
-            final Task task = getTask();
             if (getDisplayContent().mAppTransitionController.isTransitWithinTask(
                     getTransit(), task)) {
                 task.getBounds(mTmpRect);
             } else {
-                final TaskStack stack = getStack();
+                final ActivityStack stack = getStack();
                 if (stack == null) {
                     return;
                 }
@@ -5860,9 +5833,9 @@
             return;
         }
         final GraphicBuffer thumbnailHeader =
-                getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(getTask());
+                getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task);
         if (thumbnailHeader == null) {
-            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", getTask());
+            ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task);
             return;
         }
         clearThumbnail();
@@ -5886,7 +5859,7 @@
             return;
         }
         final Rect frame = win.getFrameLw();
-        final int thumbnailDrawableRes = getTask().mUserId == mWmService.mCurrentUserId
+        final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId
                 ? R.drawable.ic_account_circle
                 : R.drawable.ic_corp_badge;
         final GraphicBuffer thumbnail =
@@ -5916,7 +5889,7 @@
         final Rect insets = win != null ? win.getContentInsets() : null;
         final Configuration displayConfig = mDisplayContent.getConfiguration();
         return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked(
-                appRect, insets, thumbnailHeader, getTask(), displayConfig.uiMode,
+                appRect, insets, thumbnailHeader, task, displayConfig.uiMode,
                 displayConfig.orientation);
     }
 
@@ -6256,7 +6229,7 @@
         // Ensure the screen related fields are set. It is used to prevent activity relaunch
         // when moving between displays. For screenWidthDp and screenWidthDp, because they
         // are relative to bounds and density, they will be calculated in
-        // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be
+        // {@link Task#computeConfigResourceOverrides} and the result will also be
         // relatively fixed.
         overrideConfig.colorMode = fullConfig.colorMode;
         overrideConfig.densityDpi = fullConfig.densityDpi;
@@ -6366,9 +6339,9 @@
 
         if (rotation != ROTATION_UNDEFINED) {
             // Ensure the parent and container bounds won't overlap with insets.
-            TaskRecord.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
+            Task.intersectWithInsetsIfFits(containingAppBounds, compatDisplayBounds,
                     mCompatDisplayInsets.mNonDecorInsets[rotation]);
-            TaskRecord.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
+            Task.intersectWithInsetsIfFits(parentBounds, compatDisplayBounds,
                     mCompatDisplayInsets.mNonDecorInsets[rotation]);
         }
 
@@ -6415,7 +6388,6 @@
 
     @Override
     Rect getDisplayedBounds() {
-        final Task task = getTask();
         if (task != null) {
             final Rect overrideDisplayedBounds = task.getOverrideDisplayedBounds();
             if (!overrideDisplayedBounds.isEmpty()) {
@@ -6434,7 +6406,7 @@
         }
         // Use task-bounds if available so that activity-level letterbox (maxAspectRatio) is
         // included in the animation.
-        return getTask() != null ? getTask().getBounds() : getBounds();
+        return task != null ? task.getBounds() : getBounds();
     }
 
     /**
@@ -6504,7 +6476,6 @@
         mTmpPrevBounds.set(getBounds());
         super.onConfigurationChanged(newParentConfig);
 
-        final Task task = getTask();
         final Rect overrideBounds = getResolvedOverrideBounds();
         if (task != null && !overrideBounds.isEmpty()
                 // If the changes come from change-listener, the incoming parent configuration is
@@ -6529,7 +6500,11 @@
             updateSurfacePosition();
         }
 
-        adjustPinnedStackAndInitChangeTransitionIfNeeded(prevWinMode, getWindowingMode());
+        final int newWinMode = getWindowingMode();
+        if ((prevWinMode != newWinMode) && (mDisplayContent != null)
+                && shouldStartChangeTransition(prevWinMode, newWinMode)) {
+            initializeChangeTransition(mTmpPrevBounds);
+        }
 
         // Configuration's equality doesn't consider seq so if only seq number changes in resolved
         // override configuration. Therefore ConfigurationContainer doesn't change merged override
@@ -6563,35 +6538,25 @@
         }
     }
 
-    private void adjustPinnedStackAndInitChangeTransitionIfNeeded(int prevWinMode, int winMode) {
-        if (prevWinMode == winMode || mDisplayContent == null) {
-            return;
+    void savePinnedStackBounds() {
+        // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
+        // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
+        final ActivityStack pinnedStack = mDisplayContent.getPinnedStack();
+        if (pinnedStack == null) return;
+        final Rect stackBounds;
+        if (pinnedStack.lastAnimatingBoundsWasToFullscreen()) {
+            // We are animating the bounds, use the pre-animation bounds to save the snap
+            // fraction
+            stackBounds = pinnedStack.mPreAnimationBounds;
+        } else {
+            // We skip the animation if the fullscreen configuration is not compatible, so
+            // use the current bounds to calculate the saved snap fraction instead
+            // (see PinnedActivityStack.skipResizeAnimation())
+            stackBounds = mTmpRect;
+            pinnedStack.getBounds(stackBounds);
         }
-
-        if (prevWinMode == WINDOWING_MODE_PINNED && winMode != WINDOWING_MODE_UNDEFINED
-                && !isHidden()) {
-            // Leaving PiP to fullscreen, save the snap fraction based on the pre-animation bounds
-            // for the next re-entry into PiP (assuming the activity is not hidden or destroyed)
-            final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
-            if (pinnedStack != null) {
-                final Rect stackBounds;
-                if (pinnedStack.lastAnimatingBoundsWasToFullscreen()) {
-                    // We are animating the bounds, use the pre-animation bounds to save the snap
-                    // fraction
-                    stackBounds = pinnedStack.mPreAnimationBounds;
-                } else {
-                    // We skip the animation if the fullscreen configuration is not compatible, so
-                    // use the current bounds to calculate the saved snap fraction instead
-                    // (see PinnedActivityStack.skipResizeAnimation())
-                    stackBounds = mTmpRect;
-                    pinnedStack.getBounds(stackBounds);
-                }
-                mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(
-                        mActivityComponent, stackBounds);
-            }
-        } else if (shouldStartChangeTransition(prevWinMode, winMode)) {
-            initializeChangeTransition(mTmpPrevBounds);
-        }
+        mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(
+                mActivityComponent, stackBounds);
     }
 
     /** Returns true if the configuration is compatible with this activity. */
@@ -6686,7 +6651,7 @@
 
         // Compute configuration based on max supported width and height.
         // Also account for the left / top insets (e.g. from display cutouts), which will be clipped
-        // away later in {@link TaskRecord#computeConfigResourceOverrides()}. Otherwise, the app
+        // away later in {@link Task#computeConfigResourceOverrides()}. Otherwise, the app
         // bounds would end up too small.
         outBounds.set(containingBounds.left, containingBounds.top,
                 activityWidth + containingAppBounds.left,
@@ -6828,7 +6793,7 @@
             preserveWindow &= isResizeOnlyChange(changes);
             final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
             if (hasResizeChange) {
-                final boolean isDragResizing = getTaskRecord().isDragResizing();
+                final boolean isDragResizing = task.isDragResizing();
                 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE
                         : RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
             } else {
@@ -7435,7 +7400,7 @@
         final Rect[] mStableInsets = new Rect[4];
 
         /**
-         * Sets bounds to {@link TaskRecord} bounds. For apps in freeform, the task bounds are the
+         * Sets bounds to {@link Task} bounds. For apps in freeform, the task bounds are the
          * parent bounds from the app's perspective. No insets because within a window.
          */
         CompatDisplayInsets(DisplayContent display, Rect activityBounds, boolean isFloating) {
@@ -7495,7 +7460,6 @@
     @Override
     RemoteAnimationTarget createRemoteAnimationTarget(
             RemoteAnimationController.RemoteAnimationRecord record) {
-        final Task task = getTask();
         final WindowState mainWindow = findMainWindow();
         if (task == null || mainWindow == null) {
             return null;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 99659b0..91c909d 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -16,12 +16,15 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
+import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ITaskStackListener.FORCED_RESIZEABLE_REASON_SPLIT_SCREEN;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
@@ -33,10 +36,17 @@
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.WindowManager.DOCKED_BOTTOM;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
@@ -48,15 +58,10 @@
 import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
 
-import static com.android.server.am.ActivityStackProto.BOUNDS;
-import static com.android.server.am.ActivityStackProto.CONFIGURATION_CONTAINER;
 import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
 import static com.android.server.am.ActivityStackProto.FULLSCREEN;
-import static com.android.server.am.ActivityStackProto.ID;
 import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityStackProto.TASKS;
-import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
-import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
+import static com.android.server.am.ActivityStackProto.STACK;
 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
@@ -99,8 +104,26 @@
 import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_ACTIVITY_STACK_MSG;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
+import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
+import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
+import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.RootActivityContainer.FindTaskResult;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
+import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
+import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
+import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT;
+import static com.android.server.wm.StackProto.ANIMATING_BOUNDS;
+import static com.android.server.wm.StackProto.DEFER_REMOVAL;
+import static com.android.server.wm.StackProto.FILLS_PARENT;
+import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
+import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -125,7 +148,9 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.res.Configuration;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Debug;
@@ -139,17 +164,24 @@
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
+import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.DisplayInfo;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.logging.MetricsLoggerWrapper;
+import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DockedDividerUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.Watchdog;
 import com.android.server.am.ActivityManagerService;
@@ -168,7 +200,8 @@
 /**
  * State and management of a single stack of activities.
  */
-class ActivityStack extends ConfigurationContainer {
+class ActivityStack extends WindowContainer<Task> implements BoundsAnimationTarget,
+        ConfigurationContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStack" : TAG_ATM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_APP = TAG + POSTFIX_APP;
@@ -229,59 +262,12 @@
     /** Stack is completely invisible. */
     static final int STACK_VISIBILITY_INVISIBLE = 2;
 
-    @Override
-    protected int getChildCount() {
-        return mTaskHistory.size();
-    }
+    /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
+     * restrict IME adjustment so that a min portion of top stack remains visible.*/
+    private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
 
-    @Override
-    protected TaskRecord getChildAt(int index) {
-        return mTaskHistory.get(index);
-    }
-
-    @Override
-    protected ActivityDisplay getParent() {
-        return getDisplay();
-    }
-
-    void setParent(ActivityDisplay parent) {
-        ActivityDisplay current = getParent();
-        if (current != parent) {
-            mDisplayId = parent.mDisplayId;
-            onParentChanged(parent, current);
-        }
-    }
-
-    @Override
-    protected void onParentChanged(
-            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        if (oldParent != null) {
-            mPrevDisplayId = ((ActivityDisplay) oldParent).mDisplayId;
-        }
-
-        final ActivityDisplay display = getParent();
-        if (display != null) {
-            // Rotations are relative to the display. This means if there are 2 displays rotated
-            // differently (eg. 2 monitors with one landscape and one portrait), moving a stack
-            // from one to the other could look like a rotation change. To prevent this
-            // apparent rotation change (and corresponding bounds rotation), pretend like our
-            // current rotation is already the same as the new display.
-            // Note, if ActivityStack or related logic ever gets nested, this logic will need
-            // to move to onConfigurationChanged.
-            getConfiguration().windowConfiguration.setRotation(
-                    display.getWindowConfiguration().getRotation());
-        }
-        super.onParentChanged(newParent, oldParent);
-        if (display != null && inSplitScreenPrimaryWindowingMode()) {
-            // If we created a docked stack we want to resize it so it resizes all other stacks
-            // in the system.
-            getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
-                    mTmpRect /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
-            mStackSupervisor.resizeDockedStackLocked(getRequestedOverrideBounds(), mTmpRect,
-                    mTmpRect2, null, null, PRESERVE_WINDOWS);
-        }
-        mRootActivityContainer.updateUIDsPresentOnDisplay();
-    }
+    /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
+    private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
 
     enum ActivityState {
         INITIALIZING,
@@ -301,17 +287,11 @@
     final WindowManagerService mWindowManager;
 
     /**
-     * The back history of all previous (and possibly still
-     * running) activities.  It contains #TaskRecord objects.
-     */
-    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
-
-    /**
      * List of running activities, sorted by recent usage.
      * 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
@@ -371,17 +351,76 @@
 
     int mCurrentUser;
 
-    final int mStackId;
     /** The attached Display's unique identifier, or -1 if detached */
     int mDisplayId;
     // Id of the previous display the stack was on.
     int mPrevDisplayId = INVALID_DISPLAY;
 
+    /** Unique identifier */
+    final int mStackId;
+
+    /** For comparison with DisplayContent bounds. */
+    private Rect mTmpRect = new Rect();
+    private Rect mTmpRect2 = new Rect();
+    private Rect mTmpRect3 = new Rect();
+
+    /** For Pinned stack controlling. */
+    private Rect mTmpToBounds = new Rect();
+
+    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
+    private final Rect mAdjustedBounds = new Rect();
+
+    /**
+     * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
+     * represent the state when the animation has ended.
+     */
+    private final Rect mFullyAdjustedImeBounds = new Rect();
+
+    /** ActivityRecords that are exiting, but still on screen for animations. */
+    final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
+
+    /** Detach this stack from its display when animation completes. */
+    // TODO: maybe tie this to WindowContainer#removeChild some how...
+    private boolean mDeferRemoval;
+
+    private final Rect mTmpAdjustedBounds = new Rect();
+    private boolean mAdjustedForIme;
+    private boolean mImeGoingAway;
+    private WindowState mImeWin;
+    private float mMinimizeAmount;
+    private float mAdjustImeAmount;
+    private float mAdjustDividerAmount;
+    private final int mDockedStackMinimizeThickness;
+
+    // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
+    // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
+    // would otherwise apply while resizing, while resizing in the bounds animating mode.
+    private boolean mBoundsAnimating = false;
+    // Set when an animation has been requested but has not yet started from the UI thread. This is
+    // cleared when the animation actually starts.
+    private boolean mBoundsAnimatingRequested = false;
+    private boolean mBoundsAnimatingToFullscreen = false;
+    private boolean mCancelCurrentBoundsAnimation = false;
+    private Rect mBoundsAnimationTarget = new Rect();
+    private Rect mBoundsAnimationSourceHintBounds = new Rect();
+    private @BoundsAnimationController.AnimationType int mAnimationType;
+
+    Rect mPreAnimationBounds = new Rect();
+
+    private Dimmer mDimmer = new Dimmer(this);
+
+    /**
+     * For {@link #prepareSurfaces}.
+     */
+    private final Rect mTmpDimBoundsRect = new Rect();
+    private final Point mLastSurfaceSize = new Point();
+
+    private final AnimatingActivityRegistry mAnimatingActivityRegistry =
+            new AnimatingActivityRegistry();
+
     /** Stores the override windowing-mode from before a transient mode change (eg. split) */
     private int mRestoreOverrideWindowingMode = WINDOWING_MODE_UNDEFINED;
 
-    private final Rect mTmpRect = new Rect();
-    private final Rect mTmpRect2 = new Rect();
     private final ActivityOptions mTmpOptions = ActivityOptions.makeBasic();
 
     /** List for processing through a set of activities */
@@ -401,9 +440,6 @@
     private static final int DESTROY_ACTIVITIES_MSG = FIRST_ACTIVITY_STACK_MSG + 5;
     private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 6;
 
-    // TODO: remove after unification.
-    TaskStack mTaskStack;
-
     private static class ScheduleDestroyArgs {
         final WindowProcessController mOwner;
         final String mReason;
@@ -492,47 +528,32 @@
 
     ActivityStack(ActivityDisplay display, int stackId, ActivityStackSupervisor supervisor,
             int windowingMode, int activityType, boolean onTop) {
+        super(supervisor.mService.mWindowManager);
+        mStackId = stackId;
+        mDockedStackMinimizeThickness =
+                supervisor.mService.mWindowManager.mContext.getResources().getDimensionPixelSize(
+                        com.android.internal.R.dimen.docked_stack_minimize_thickness);
+        EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_CREATED, stackId);
         mStackSupervisor = supervisor;
         mService = supervisor.mService;
         mRootActivityContainer = mService.mRootActivityContainer;
         mHandler = new ActivityStackHandler(supervisor.mLooper);
         mWindowManager = mService.mWindowManager;
-        mStackId = stackId;
         mCurrentUser = mService.mAmInternal.getCurrentUserId();
         // Set display id before setting activity and window type to make sure it won't affect
         // stacks on a wrong display.
         mDisplayId = display.mDisplayId;
         setActivityType(activityType);
-        createTaskStack(display.mDisplayId, onTop, mTmpRect2);
+        display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
         setWindowingMode(windowingMode, false /* animate */, false /* showRecents */,
                 false /* enteringSplitScreenMode */, false /* deferEnsuringVisibility */,
                 true /* creating */);
-        display.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
-    }
-
-    void createTaskStack(int displayId, boolean onTop, Rect outBounds) {
-        final DisplayContent dc = mWindowManager.mRoot.getDisplayContent(displayId);
-        if (dc == null) {
-            throw new IllegalArgumentException("Trying to add stackId=" + mStackId
-                    + " to unknown displayId=" + displayId);
-        }
-        mTaskStack = new TaskStack(mWindowManager, mStackId, this);
-        dc.setStackOnDisplay(mStackId, onTop, mTaskStack);
-        if (mTaskStack.matchParentBounds()) {
-            outBounds.setEmpty();
-        } else {
-            mTaskStack.getRawBounds(outBounds);
-        }
-    }
-
-    TaskStack getTaskStack() {
-        return mTaskStack;
     }
 
     /**
      * This should be called when an activity in a child task changes state. This should only
      * be called from
-     * {@link TaskRecord#onActivityStateChanged(ActivityRecord, ActivityState, String)}.
+     * {@link Task#onActivityStateChanged(ActivityRecord, ActivityState, String)}.
      * @param record The {@link ActivityRecord} whose state has changed.
      * @param state The new state.
      * @param reason The reason for the change.
@@ -549,7 +570,7 @@
             if (record == mRootActivityContainer.getTopResumedActivity()) {
                 mService.setResumedActivityUncheckLocked(record, reason);
             }
-            mStackSupervisor.mRecentTasks.add(record.getTaskRecord());
+            mStackSupervisor.mRecentTasks.add(record.getTask());
         }
     }
 
@@ -567,8 +588,29 @@
         getBounds(newBounds);
 
         super.onConfigurationChanged(newParentConfig);
+
+        // Only need to update surface size here since the super method will handle updating
+        // surface position.
+        updateSurfaceSize(getPendingTransaction());
+
+        if (mDisplayContent == null) {
+            return;
+        }
+
+        if (prevWindowingMode != getWindowingMode()) {
+            mDisplayContent.onStackWindowingModeChanged(this);
+
+            if (inSplitScreenSecondaryWindowingMode()) {
+                // When the stack is resized due to entering split screen secondary, offset the
+                // windows to compensate for the new stack position.
+                forAllWindows(w -> {
+                    w.mWinAnimator.setOffsetPositionForStackResize(true);
+                }, true);
+            }
+        }
+
         final ActivityDisplay display = getDisplay();
-        if (display == null || getTaskStack() == null) {
+        if (display == null ) {
             return;
         }
 
@@ -579,7 +621,7 @@
         // Use override windowing mode to prevent extra bounds changes if inheriting the mode.
         if (overrideWindowingMode == WINDOWING_MODE_PINNED) {
             // Pinned calculation already includes rotation
-            hasNewOverrideBounds = getTaskStack().calculatePinnedBoundsForConfigChange(newBounds);
+            hasNewOverrideBounds = calculatePinnedBoundsForConfigChange(newBounds);
         } else if (!matchParentBounds()) {
             // If the parent (display) has rotated, rotate our bounds to best-fit where their
             // bounds were on the pre-rotated display.
@@ -601,7 +643,7 @@
                         || prevDensity != getConfiguration().densityDpi
                         || prevScreenW != getConfiguration().screenWidthDp
                         || prevScreenH != getConfiguration().screenHeightDp) {
-                    getTaskStack().calculateDockedBoundsForConfigChange(newParentConfig, newBounds);
+                    calculateDockedBoundsForConfigChange(newParentConfig, newBounds);
                     hasNewOverrideBounds = true;
                 }
             }
@@ -622,7 +664,7 @@
                 final boolean isMinimizedDock =
                         display.mDisplayContent.getDockedDividerController().isMinimizedDock();
                 if (isMinimizedDock) {
-                    TaskRecord topTask = display.getSplitScreenPrimaryStack().topTask();
+                    Task topTask = display.getSplitScreenPrimaryStack().topTask();
                     if (topTask != null) {
                         dockedBounds = topTask.getBounds();
                     }
@@ -699,7 +741,7 @@
         final int currentMode = getWindowingMode();
         final int currentOverrideMode = getRequestedOverrideWindowingMode();
         final ActivityDisplay display = getDisplay();
-        final TaskRecord topTask = topTask();
+        final Task topTask = topTask();
         final ActivityStack splitScreenStack = display.getSplitScreenPrimaryStack();
         int windowingMode = preferredWindowingMode;
         if (preferredWindowingMode == WINDOWING_MODE_UNDEFINED
@@ -766,8 +808,8 @@
                     : WINDOWING_MODE_FULLSCREEN;
         }
         if (sendNonResizeableNotification && likelyResolvedMode != WINDOWING_MODE_FULLSCREEN
-                && topActivity != null && topActivity.isNonResizableOrForcedResizable()
-                && !topActivity.noDisplay) {
+                && topActivity != null && !topActivity.noDisplay
+                && topActivity.isNonResizableOrForcedResizable(likelyResolvedMode)) {
             // Inform the user that they are starting an app that may not work correctly in
             // multi-window mode.
             final String packageName = topActivity.info.applicationInfo.packageName;
@@ -804,10 +846,10 @@
 
             mTmpRect2.setEmpty();
             if (windowingMode != WINDOWING_MODE_FULLSCREEN) {
-                if (mTaskStack.matchParentBounds()) {
+                if (matchParentBounds()) {
                     mTmpRect2.setEmpty();
                 } else {
-                    mTaskStack.getRawBounds(mTmpRect2);
+                    getRawBounds(mTmpRect2);
                 }
             }
 
@@ -859,27 +901,6 @@
         return super.isCompatible(windowingMode, activityType);
     }
 
-    /** Adds the stack to specified display and calls WindowManager to do the same. */
-    void reparent(ActivityDisplay activityDisplay, boolean onTop, boolean displayRemoved) {
-        // TODO: We should probably resolve the windowing mode for the stack on the new display here
-        // so that it end up in a compatible mode in the new display. e.g. split-screen secondary.
-        removeFromDisplay();
-        // Reparent the window container before we try to update the position when adding it to
-        // the new display below
-        mTmpRect2.setEmpty();
-        if (mTaskStack == null) {
-            // TODO: Remove after unification.
-            Log.w(TAG, "Task stack is not valid when reparenting.");
-        } else {
-            mTaskStack.reparent(activityDisplay.mDisplayId, mTmpRect2, onTop);
-        }
-        setBounds(mTmpRect2.isEmpty() ? null : mTmpRect2);
-        activityDisplay.addChild(this, onTop ? POSITION_TOP : POSITION_BOTTOM);
-        if (!displayRemoved) {
-            postReparent();
-        }
-    }
-
     /** Resume next focusable stack after reparenting to another display. */
     void postReparent() {
         adjustFocusToNextFocusableStack("reparent", true /* allowFocusSelf */);
@@ -890,100 +911,11 @@
                 !PRESERVE_WINDOWS);
     }
 
-    /**
-     * Updates the inner state of the stack to remove it from its current parent, so it can be
-     * either destroyed completely or re-parented.
-     */
-    private void removeFromDisplay() {
-        final ActivityDisplay display = getDisplay();
-        if (display != null) {
-            display.removeChild(this);
-        }
-        mDisplayId = INVALID_DISPLAY;
-    }
-
-    /** Removes the stack completely. Also calls WindowManager to do the same on its side. */
-    void remove() {
-        final ActivityDisplay oldDisplay = getDisplay();
-        removeFromDisplay();
-        if (mTaskStack != null) {
-            mTaskStack.removeIfPossible();
-            mTaskStack = null;
-        }
-        onParentChanged(null, oldDisplay);
-    }
-
     ActivityDisplay getDisplay() {
         return mRootActivityContainer.getActivityDisplay(mDisplayId);
     }
 
     /**
-     * @see #getStackDockedModeBounds(Rect, Rect, Rect, Rect)
-     */
-    void getStackDockedModeBounds(Rect dockedBounds, Rect currentTempTaskBounds,
-            Rect outStackBounds, Rect outTempTaskBounds) {
-        if (mTaskStack != null) {
-            mTaskStack.getStackDockedModeBoundsLocked(getParent().getConfiguration(), dockedBounds,
-                    currentTempTaskBounds, outStackBounds, outTempTaskBounds);
-        } else {
-            outStackBounds.setEmpty();
-            outTempTaskBounds.setEmpty();
-        }
-    }
-
-    void prepareFreezingTaskBounds() {
-        if (mTaskStack != null) {
-            // TODO: This cannot be false after unification.
-            mTaskStack.prepareFreezingTaskBounds();
-        }
-    }
-
-    void getWindowContainerBounds(Rect outBounds) {
-        if (mTaskStack != null) {
-            mTaskStack.getBounds(outBounds);
-            return;
-        }
-        outBounds.setEmpty();
-    }
-
-    void positionChildWindowContainerAtTop(TaskRecord child) {
-        if (mTaskStack != null) {
-            // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtTop(child, true /* includingParents */);
-        }
-    }
-
-    void positionChildWindowContainerAtBottom(TaskRecord child) {
-        // If there are other focusable stacks on the display, the z-order of the display should not
-        // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
-        // task to bottom, the next focusable stack on the same display should be focused.
-        final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
-                child.getStack(), true /* ignoreCurrent */);
-        if (mTaskStack != null) {
-            // TODO: Remove after unification. This cannot be false after that.
-            mTaskStack.positionChildAtBottom(child,
-                    nextFocusableStack == null /* includingParents */);
-        }
-    }
-
-    /**
-     * Returns whether to defer the scheduling of the multi-window mode.
-     */
-    boolean deferScheduleMultiWindowModeChanged() {
-        if (inPinnedWindowingMode()) {
-            // For the pinned stack, the deferring of the multi-window mode changed is tied to the
-            // transition animation into picture-in-picture, and is called once the animation
-            // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
-            // state.
-            // @see BoundsAnimationController
-            // @see BoundsAnimationControllerTests
-            if (getTaskStack() == null) return false;
-            return getTaskStack().deferScheduleMultiWindowModeChanged();
-        }
-        return false;
-    }
-
-    /**
      * Defers updating the bounds of the stack. If the stack was resized/repositioned while
      * deferring, the bounds will update in {@link #continueUpdateBounds()}.
      */
@@ -1038,11 +970,6 @@
         return false;
     }
 
-    @Override
-    public int setBounds(Rect bounds) {
-        return super.setBounds(!inMultiWindowMode() ? null : bounds);
-    }
-
     ActivityRecord topRunningActivityLocked() {
         return topRunningActivityLocked(false /* focusableOnly */);
     }
@@ -1066,7 +993,7 @@
 
     ActivityRecord topRunningNonOverlayTaskActivity() {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (!r.finishing && !r.mTaskOverlay) {
@@ -1079,7 +1006,7 @@
 
     ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (!r.finishing && !r.delayedResume && r != notTop && r.okToShowLocked()) {
@@ -1101,7 +1028,7 @@
      */
     final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            TaskRecord task = getChildAt(taskNdx);
+            Task task = getChildAt(taskNdx);
             if (task.mTaskId == taskId) {
                 continue;
             }
@@ -1126,7 +1053,7 @@
         return null;
     }
 
-    final TaskRecord topTask() {
+    final Task topTask() {
         final int size = getChildCount();
         if (size > 0) {
             return getChildAt(size - 1);
@@ -1134,9 +1061,9 @@
         return null;
     }
 
-    TaskRecord taskForIdLocked(int id) {
+    Task taskForIdLocked(int id) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             if (task.mTaskId == id) {
                 return task;
             }
@@ -1153,9 +1080,9 @@
         if (r == null) {
             return null;
         }
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         final ActivityStack stack = r.getActivityStack();
-        if (stack != null && task.mChildren.contains(r) && mTaskHistory.contains(task)) {
+        if (stack != null && task.mChildren.contains(r) && mChildren.contains(task)) {
             if (stack != this) Slog.w(TAG,
                     "Illegal state! task does not point to stack it is in.");
             return r;
@@ -1163,14 +1090,14 @@
         return null;
     }
 
-    boolean isInStackLocked(TaskRecord task) {
-        return mTaskHistory.contains(task);
+    boolean isInStackLocked(Task task) {
+        return mChildren.contains(task);
     }
 
     /** Checks if there are tasks with specific UID in the stack. */
     boolean isUidPresent(int uid) {
         for (int j = getChildCount() - 1; j >= 0; --j) {
-            final TaskRecord task = getChildAt(j);
+            final Task task = getChildAt(j);
             for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
                 final ActivityRecord r = task.getChildAt(i);
                 if (r.getUid() == uid) {
@@ -1184,7 +1111,7 @@
     /** Get all UIDs that are present in the stack. */
     void getPresentUIDs(IntArray presentUIDs) {
         for (int j = getChildCount() - 1; j >= 0; --j) {
-            final TaskRecord task = getChildAt(j);
+            final Task task = getChildAt(j);
             for (int i = task.getChildCount() - 1; i >= 0 ; --i) {
                 final ActivityRecord r = task.getChildAt(i);
                 presentUIDs.add(r.getUid());
@@ -1199,14 +1126,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() {
@@ -1231,7 +1159,7 @@
      * @param reason The reason for moving the stack to the front.
      * @param task If non-null, the task will be moved to the top of the stack.
      * */
-    void moveToFront(String reason, TaskRecord task) {
+    void moveToFront(String reason, Task task) {
         if (!isAttached()) {
             return;
         }
@@ -1265,7 +1193,7 @@
         display.positionChildAtTop(this, !movingTask /* includingParents */, reason);
         if (movingTask) {
             // This also moves the entire hierarchy branch to top, including parents
-            insertTaskAtTop(task, null /* starting */);
+            positionChildAtTop(task);
         }
     }
 
@@ -1273,14 +1201,14 @@
      * @param reason The reason for moving the stack to the back.
      * @param task If non-null, the task will be moved to the bottom of the stack.
      **/
-    void moveToBack(String reason, TaskRecord task) {
+    void moveToBack(String reason, Task task) {
         if (!isAttached()) {
             return;
         }
 
         getDisplay().positionChildAtBottom(this, reason);
         if (task != null) {
-            insertTaskAtBottom(task);
+            positionChildAtBottom(task);
         }
 
         /**
@@ -1301,7 +1229,8 @@
         return isFocusable() && shouldBeVisible(null /* starting */);
     }
 
-    final boolean isAttached() {
+    @Override
+    public boolean isAttached() {
         final ActivityDisplay display = getDisplay();
         return display != null && !display.isRemoved();
     }
@@ -1324,7 +1253,7 @@
 
         if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             if (task.voiceSession != null) {
                 // We never match voice sessions; those always run independently.
                 if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
@@ -1365,7 +1294,7 @@
 
             if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
                     + (task.realActivity != null ? task.realActivity.flattenToShortString() : "")
-                    + "/aff=" + r.getTaskRecord().rootAffinity + " to new cls="
+                    + "/aff=" + r.getTask().rootAffinity + " to new cls="
                     + intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
             // TODO Refactor to remove duplications. Check if logic can be simplified.
             if (task.realActivity != null && task.realActivity.compareTo(cls) == 0
@@ -1415,7 +1344,7 @@
         final int userId = UserHandle.getUserId(info.applicationInfo.uid);
 
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (!r.okToShowLocked()) {
@@ -1438,29 +1367,22 @@
         return null;
     }
 
-    /*
-     * Move the activities around in the stack to bring a user to the foreground.
-     */
-    final void switchUserLocked(int userId) {
+    // TODO: Should each user have there own stacks?
+    @Override
+    void switchUser(int userId) {
         if (mCurrentUser == userId) {
             return;
         }
         mCurrentUser = userId;
 
-        // Move userId's tasks to the top.
-        int index = getChildCount();
-        for (int i = 0; i < index; ) {
-            final TaskRecord task = getChildAt(i);
-
-            if (task.okToShowLocked()) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "switchUser: stack=" + getStackId() +
-                        " moving " + task + " to top");
-                mTaskHistory.remove(i);
-                mTaskHistory.add(task);
-                --index;
-                // Use same value for i.
-            } else {
-                ++i;
+        super.switchUser(userId);
+        int top = mChildren.size();
+        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
+            Task task = mChildren.get(taskNdx);
+            if (mWmService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
+                mChildren.remove(taskNdx);
+                mChildren.add(task);
+                --top;
             }
         }
     }
@@ -1483,7 +1405,7 @@
     void awakeFromSleepingLocked() {
         // Ensure activities are no longer sleeping.
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 r.setSleeping(false);
@@ -1500,7 +1422,7 @@
         final int userId = UserHandle.getUserId(aInfo.uid);
 
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord ar = task.getChildAt(activityNdx);
 
@@ -1578,7 +1500,7 @@
         // Make sure any paused or stopped but visible activities are now sleeping.
         // This ensures that the activity's onStop() is called.
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
@@ -1644,7 +1566,7 @@
         mLastNoHistoryActivity = (prev.intent.getFlags() & Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
                 || (prev.info.flags & ActivityInfo.FLAG_NO_HISTORY) != 0 ? prev : null;
         prev.setState(PAUSING, "startPausingLocked");
-        prev.getTaskRecord().touchActiveTime();
+        prev.getTask().touchActiveTime();
         clearLaunchTime(prev);
 
         mService.updateCpuStats();
@@ -1862,7 +1784,7 @@
             return true;
         }
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
 
@@ -2043,7 +1965,7 @@
     final int rankTaskLayers(int baseLayer) {
         int layer = 0;
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             ActivityRecord r = task.topRunningActivityLocked();
             if (r == null || r.finishing || !r.visible) {
                 task.mLayerRank = -1;
@@ -2094,7 +2016,7 @@
             final boolean resumeTopActivity = isFocusable() && isInStackLocked(starting) == null
                     && top != null && !top.mLaunchTaskBehind;
             for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-                final TaskRecord task = getChildAt(taskNdx);
+                final Task task = getChildAt(taskNdx);
                 for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r = task.getChildAt(activityNdx);
                     final boolean isTop = r == top;
@@ -2213,7 +2135,7 @@
 
     @Override
     public boolean supportsSplitScreenWindowingMode() {
-        final TaskRecord topTask = topTask();
+        final Task topTask = topTask();
         return super.supportsSplitScreenWindowingMode()
                 && (topTask == null || topTask.supportsSplitScreenWindowingMode());
     }
@@ -2338,7 +2260,7 @@
 
     void clearOtherAppTimeTrackers(AppTimeTracker except) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if ( r.appTimeTracker != except) {
@@ -2412,7 +2334,7 @@
 
         final ActivityRecord topActivity = topRunningActivityLocked();
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (aboveTop) {
@@ -2726,7 +2648,7 @@
                     dc.prepareAppTransition(TRANSIT_NONE, false);
                 } else {
                     dc.prepareAppTransition(
-                            prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_CLOSE
+                            prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_CLOSE
                                     : TRANSIT_TASK_CLOSE, false);
                 }
                 prev.setVisibility(false);
@@ -2738,7 +2660,7 @@
                     dc.prepareAppTransition(TRANSIT_NONE, false);
                 } else {
                     dc.prepareAppTransition(
-                            prev.getTaskRecord() == next.getTaskRecord() ? TRANSIT_ACTIVITY_OPEN
+                            prev.getTask() == next.getTask() ? TRANSIT_ACTIVITY_OPEN
                                     : next.mLaunchTaskBehind ? TRANSIT_TASK_OPEN_BEHIND
                                             : TRANSIT_TASK_OPEN, false);
                 }
@@ -2798,7 +2720,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.
@@ -2864,7 +2786,7 @@
                 next.notifyAppResumed(next.stopped);
 
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.mUserId,
-                        System.identityHashCode(next), next.getTaskRecord().mTaskId,
+                        System.identityHashCode(next), next.getTask().mTaskId,
                         next.shortComponentName);
 
                 next.sleeping = false;
@@ -2960,73 +2882,9 @@
         return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
     }
 
-    /** Returns the position the input task should be placed in this stack. */
-    int getAdjustedPositionForTask(TaskRecord task, int suggestedPosition,
-            ActivityRecord starting) {
-
-        int maxPosition = getChildCount();
-        if ((starting != null && starting.okToShowLocked())
-                || (starting == null && task.okToShowLocked())) {
-            // If the task or starting activity can be shown, then whatever position is okay.
-            return Math.min(suggestedPosition, maxPosition);
-        }
-
-        // The task can't be shown, put non-current user tasks below current user tasks.
-        while (maxPosition > 0) {
-            final TaskRecord tmpTask = getChildAt(maxPosition - 1);
-            if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.mUserId)
-                    || tmpTask.topRunningActivityLocked() == null) {
-                break;
-            }
-            maxPosition--;
-        }
-
-        return  Math.min(suggestedPosition, maxPosition);
-    }
-
-    /**
-     * Used from {@link ActivityStack#positionTask(TaskRecord, int)}.
-     * @see ActivityTaskManagerService#positionTaskInStack(int, int, int).
-     */
-    private void insertTaskAtPosition(TaskRecord task, int position) {
-        if (position >= getChildCount()) {
-            insertTaskAtTop(task, null);
-            return;
-        } else if (position <= 0) {
-            insertTaskAtBottom(task);
-            return;
-        }
-        position = getAdjustedPositionForTask(task, position, null /* starting */);
-        mTaskHistory.remove(task);
-        mTaskHistory.add(position, task);
-        if (mTaskStack != null) {
-            // TODO: this can not be false after unification Stack.
-            mTaskStack.positionChildAt(task, position);
-        }
-        task.updateTaskMovement(true);
-    }
-
-    void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
-        // TODO: Better place to put all the code below...may be addChild...
-        mTaskHistory.remove(task);
-        // Now put task at top.
-        final int position = getAdjustedPositionForTask(task, getChildCount(), starting);
-        mTaskHistory.add(position, task);
-        task.updateTaskMovement(true);
-        positionChildWindowContainerAtTop(task);
-    }
-
-    private void insertTaskAtBottom(TaskRecord task) {
-        mTaskHistory.remove(task);
-        final int position = getAdjustedPositionForTask(task, 0, null);
-        mTaskHistory.add(position, task);
-        task.updateTaskMovement(true);
-        positionChildWindowContainerAtBottom(task);
-    }
-
     void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
             boolean newTask, boolean keepCurTransition, ActivityOptions options) {
-        TaskRecord rTask = r.getTaskRecord();
+        Task rTask = r.getTask();
         final int taskId = rTask.mTaskId;
         final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
         // mLaunchTaskBehind tasks get placed at the back of the task stack.
@@ -3035,9 +2893,9 @@
             // Last activity in task had been removed or ActivityManagerService is reusing task.
             // Insert or replace.
             // Might not even be in.
-            insertTaskAtTop(rTask, r);
+            positionChildAtTop(rTask);
         }
-        TaskRecord task = null;
+        Task task = null;
         if (!newTask) {
             // If starting in an existing task, find where that is...
             boolean startIt = true;
@@ -3069,8 +2927,8 @@
 
         // If we are not placing the new activity frontmost, we do not want to deliver the
         // onUserLeaving callback to the actual frontmost activity
-        final TaskRecord activityTask = r.getTaskRecord();
-        if (task == activityTask && mTaskHistory.indexOf(task) != (getChildCount() - 1)) {
+        final Task activityTask = r.getTask();
+        if (task == activityTask && mChildren.indexOf(task) != (getChildCount() - 1)) {
             mStackSupervisor.mUserLeaving = false;
             if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
                     "startActivity() behind front, mUserLeaving=false");
@@ -3142,12 +3000,12 @@
                 // "has the same starting icon" as the next one.  This allows the
                 // window manager to keep the previous window it had previously
                 // created, if it still had one.
-                TaskRecord prevTask = r.getTaskRecord();
+                Task prevTask = r.getTask();
                 ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked();
                 if (prev != null) {
                     // We don't want to reuse the previous starting preview if:
                     // (1) The current activity is in a different task.
-                    if (prev.getTaskRecord() != prevTask) {
+                    if (prev.getTask() != prevTask) {
                         prev = null;
                     }
                     // (2) The current activity is already displayed.
@@ -3170,7 +3028,7 @@
      * {@param toFrontActivity} should be set.
      */
     private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate,
-            TaskRecord toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
+            Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
         if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) {
             // Ensure the caller has requested not to trigger auto-enter PiP
             return false;
@@ -3190,7 +3048,7 @@
 
     private boolean isTaskSwitch(ActivityRecord r,
             ActivityRecord topFocusedActivity) {
-        return topFocusedActivity != null && r.getTaskRecord() != topFocusedActivity.getTaskRecord();
+        return topFocusedActivity != null && r.getTask() != topFocusedActivity.getTask();
     }
 
     /**
@@ -3200,7 +3058,7 @@
      * @param forceReset Flag indicating if clear task was requested
      * @return An ActivityOptions that needs to be processed.
      */
-    private ActivityOptions resetTargetTaskIfNeededLocked(TaskRecord task, boolean forceReset) {
+    private ActivityOptions resetTargetTaskIfNeededLocked(Task task, boolean forceReset) {
         ActivityOptions topOptions = null;
 
         // Tracker of the end of currently handled reply chain (sublist) of activities. What happens
@@ -3254,19 +3112,19 @@
                 // moved.
                 // TODO: We should probably look for other stacks also, since corresponding task
                 // with the same affinity is unlikely to be in the same stack.
-                final TaskRecord targetTask;
+                final Task targetTask;
                 final ActivityRecord bottom =
                         hasChild() && getChildAt(0).hasChild() ?
                                 getChildAt(0).getChildAt(0) : null;
-                if (bottom != null && target.taskAffinity.equals(bottom.getTaskRecord().affinity)) {
+                if (bottom != null && target.taskAffinity.equals(bottom.getTask().affinity)) {
                     // If the activity currently at the bottom has the
                     // same task affinity as the one we are moving,
                     // then merge it into the same task.
-                    targetTask = bottom.getTaskRecord();
+                    targetTask = bottom.getTask();
                     if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Start pushing activity " + target
                             + " out to bottom task " + targetTask);
                 } else {
-                    targetTask = createTaskRecord(
+                    targetTask = createTask(
                             mStackSupervisor.getNextTaskIdForUserLocked(target.mUserId),
                             target.info, null /* intent */, null /* voiceSession */,
                             null /* voiceInteractor */, false /* toTop */);
@@ -3299,7 +3157,7 @@
                     p.reparent(targetTask, 0 /* position - bottom */, "resetTargetTaskIfNeeded");
                 }
 
-                positionChildWindowContainerAtBottom(targetTask);
+                positionChildAtBottom(targetTask);
                 mStackSupervisor.mRecentTasks.add(targetTask);
                 replyChainEnd = -1;
             } else if (forceReset || finishOnTaskLaunch || clearWhenTaskReset) {
@@ -3359,7 +3217,7 @@
             if (singleTaskInstanceDisplay || display.alwaysCreateStack(getWindowingMode(),
                     getActivityType())) {
                 for (int index = numTasksCreated - 1; index >= 0; index--) {
-                    final TaskRecord targetTask = getChildAt(index);
+                    final Task targetTask = getChildAt(index);
                     final ActivityStack targetStack = display.getOrCreateStack(getWindowingMode(),
                             getActivityType(), false /* onTop */);
                     targetTask.reparent(targetStack, false /* toTop */,
@@ -3374,7 +3232,7 @@
 
     /**
      * Helper method for {@link #resetTaskIfNeededLocked(ActivityRecord, ActivityRecord)}.
-     * Processes all of the activities in a given TaskRecord looking for an affinity with the task
+     * Processes all of the activities in a given Task looking for an affinity with the task
      * of resetTaskIfNeededLocked.taskTop.
      * @param affinityTask The task we are looking for an affinity to.
      * @param task Task that resetTaskIfNeededLocked.taskTop belongs to.
@@ -3382,7 +3240,7 @@
      * @param forceReset Flag indicating if clear task was requested
      */
     // TODO: Consider merging with #resetTargetTaskIfNeededLocked() above
-    private int resetAffinityTaskIfNeededLocked(TaskRecord affinityTask, TaskRecord task,
+    private int resetAffinityTaskIfNeededLocked(Task affinityTask, Task task,
             boolean topTaskIsHigher, boolean forceReset, int taskInsertionPoint) {
         // Tracker of the end of currently handled reply chain (sublist) of activities. What happens
         // to activities in the same chain will depend on what the end activity of the chain needs.
@@ -3460,7 +3318,7 @@
                         if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Pulling activity " + p
                                 + " from " + srcPos + " in to resetting task " + task);
                     }
-                    positionChildWindowContainerAtTop(task);
+                    positionChildAtTop(task);
 
                     // Now we've moved it in to place...  but what if this is
                     // a singleTop activity and we have put it on top of another
@@ -3498,9 +3356,9 @@
             ActivityRecord newActivity) {
         final boolean forceReset =
                 (newActivity.info.flags & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
-        final TaskRecord task = taskTop.getTaskRecord();
+        final Task task = taskTop.getTask();
 
-        // False until we evaluate the TaskRecord associated with taskTop. Switches to true
+        // False until we evaluate the Task associated with taskTop. Switches to true
         // for remaining tasks. Used for later tasks to reparent to task.
         boolean taskFound = false;
 
@@ -3511,7 +3369,7 @@
         int reparentInsertionPoint = -1;
 
         for (int i = getChildCount() - 1; i >= 0; --i) {
-            final TaskRecord targetTask = getChildAt(i);
+            final Task targetTask = getChildAt(i);
 
             if (targetTask == task) {
                 topOptions = resetTargetTaskIfNeededLocked(task, forceReset);
@@ -3522,7 +3380,7 @@
             }
         }
 
-        int taskNdx = mTaskHistory.indexOf(task);
+        int taskNdx = mChildren.indexOf(task);
         if (taskNdx >= 0) {
             ActivityRecord newTop = getChildAt(taskNdx).getTopActivity();
             if (newTop != null) {
@@ -3588,7 +3446,7 @@
     /** Finish all activities that were started for result from the specified activity. */
     final void finishSubActivityLocked(ActivityRecord self, String resultWho, int requestCode) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (r.resultTo == self && r.requestCode == requestCode) {
@@ -3610,17 +3468,17 @@
      * @return The task that was finished in this stack, {@code null} if top running activity does
      *         not belong to the crashed app.
      */
-    final TaskRecord finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
+    final Task finishTopCrashedActivityLocked(WindowProcessController app, String reason) {
         ActivityRecord r = topRunningActivityLocked();
-        TaskRecord finishedTask = null;
+        Task finishedTask = null;
         if (r == null || r.app != app) {
             return null;
         }
         Slog.w(TAG, "  Force finishing activity "
                 + r.intent.getComponent().flattenToShortString());
-        finishedTask = r.getTaskRecord();
-        int taskNdx = mTaskHistory.indexOf(finishedTask);
-        final TaskRecord task = finishedTask;
+        finishedTask = r.getTask();
+        int taskNdx = mChildren.indexOf(finishedTask);
+        final Task task = finishedTask;
         int activityNdx = task.mChildren.indexOf(r);
         getDisplay().mDisplayContent.prepareAppTransition(
                 TRANSIT_CRASHING_ACTIVITY_CLOSE, false /* alwaysKeepCurrent */);
@@ -3656,7 +3514,7 @@
         IBinder sessionBinder = session.asBinder();
         boolean didOne = false;
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            TaskRecord tr = getChildAt(taskNdx);
+            Task tr = getChildAt(taskNdx);
             if (tr.voiceSession != null && tr.voiceSession.asBinder() == sessionBinder) {
                 for (int activityNdx = tr.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                     ActivityRecord r = tr.getChildAt(activityNdx);
@@ -3694,7 +3552,7 @@
     void finishAllActivitiesImmediately() {
         boolean noActivitiesInStack = true;
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 noActivitiesInStack = false;
@@ -3703,7 +3561,7 @@
             }
         }
         if (noActivitiesInStack) {
-            remove();
+            removeIfPossible();
         }
     }
 
@@ -3724,15 +3582,15 @@
     boolean shouldUpRecreateTaskLocked(ActivityRecord srec, String destAffinity) {
         // Basic case: for simple app-centric recents, we need to recreate
         // the task if the affinity has changed.
-        if (srec == null || srec.getTaskRecord().affinity == null ||
-                !srec.getTaskRecord().affinity.equals(destAffinity)) {
+        if (srec == null || srec.getTask().affinity == null
+                || !srec.getTask().affinity.equals(destAffinity)) {
             return true;
         }
         // Document-centric case: an app may be split in to multiple documents;
         // they need to re-create their task if this current activity is the root
         // of a document, unless simply finishing it will return them to the the
         // correct app behind.
-        final TaskRecord task = srec.getTaskRecord();
+        final Task task = srec.getTask();
         if (srec.isRootOfTask() && task.getBaseIntent() != null
                 && task.getBaseIntent().isDocument()) {
             // Okay, this activity is at the root of its task.  What to do, what to do...
@@ -3741,12 +3599,12 @@
                 return true;
             }
             // We now need to get the task below it to determine what to do.
-            int taskIdx = mTaskHistory.indexOf(task);
+            int taskIdx = mChildren.indexOf(task);
             if (taskIdx <= 0) {
                 Slog.w(TAG, "shouldUpRecreateTask: task not in history for " + srec);
                 return false;
             }
-            final TaskRecord prevTask = getChildAt(taskIdx);
+            final Task prevTask = getChildAt(taskIdx);
             if (!task.affinity.equals(prevTask.affinity)) {
                 // These are different apps, so need to recreate.
                 return true;
@@ -3757,10 +3615,10 @@
 
     final boolean navigateUpToLocked(ActivityRecord srec, Intent destIntent, int resultCode,
             Intent resultData) {
-        final TaskRecord task = srec.getTaskRecord();
+        final Task task = srec.getTask();
         final ArrayList<ActivityRecord> activities = task.mChildren;
         final int start = activities.indexOf(srec);
-        if (!mTaskHistory.contains(task) || (start < 0)) {
+        if (!mChildren.contains(task) || (start < 0)) {
             return false;
         }
         int finishTo = start - 1;
@@ -3852,15 +3710,10 @@
      * an activity moves away from the stack.
      */
     void onActivityRemovedFromStack(ActivityRecord r) {
-        removeActivityFromLRUList(r);
         removeTimeoutsForActivity(r);
 
-        // TODO(stack-unify): null check will no longer be needed.
-        if (mTaskStack != null) {
-            mTaskStack.mExitingActivities.remove(r);
-        }
-        // TODO(stack-unify): Remove if no bugs showed up...
-        //r.mIsExiting = false;
+        mExitingActivities.remove(r);
+        mLruActivities.remove(r);
 
         if (mResumedActivity != null && mResumedActivity == r) {
             setResumedActivity(null, "onActivityRemovedFromStack");
@@ -3871,9 +3724,12 @@
     }
 
     void onActivityAddedToStack(ActivityRecord r) {
-        if(r.getState() == RESUMED) {
+        if (r.isState(RESUMED)) {
             setResumedActivity(r, "onActivityAddedToStack");
         }
+        if (r.hasProcess()) {
+            updateLruList(r);
+        }
     }
 
     /// HANDLER INTERFACE BEGIN
@@ -3938,7 +3794,7 @@
         boolean lastIsOpaque = false;
         boolean activityRemoved = false;
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (r.finishing) {
@@ -3969,7 +3825,7 @@
         }
     }
 
-    final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<TaskRecord> tasks,
+    final int releaseSomeActivitiesLocked(WindowProcessController app, ArraySet<Task> tasks,
             String reason) {
         // Iterate over tasks starting at the back (oldest) first.
         if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + app);
@@ -3979,7 +3835,7 @@
         }
         int numReleased = 0;
         for (int taskNdx = 0; taskNdx < getChildCount() && maxTasks > 0; taskNdx++) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             if (!tasks.contains(task)) {
                 continue;
             }
@@ -4031,7 +3887,7 @@
     }
 
     private boolean removeHistoryRecordsForAppLocked(WindowProcessController app) {
-        removeHistoryRecordsForAppLocked(mLRUActivities, app, "mLRUActivities");
+        removeHistoryRecordsForAppLocked(mLruActivities, app, "mLruActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mStoppingActivities, app,
                 "mStoppingActivities");
         removeHistoryRecordsForAppLocked(mStackSupervisor.mGoingToSleepActivities, app,
@@ -4104,7 +3960,7 @@
                             Slog.w(TAG, "Force removing " + r + ": app died, no saved state");
                             EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
                                     r.mUserId, System.identityHashCode(r),
-                                    r.getTaskRecord().mTaskId, r.shortComponentName,
+                                    r.getTask().mTaskId, r.shortComponentName,
                                     "proc died without state saved");
                         }
                     } else {
@@ -4143,14 +3999,14 @@
         getDisplay().mDisplayContent.prepareAppTransition(transit, false);
     }
 
-    final void moveTaskToFrontLocked(TaskRecord tr, boolean noAnimation, ActivityOptions options,
+    final void moveTaskToFrontLocked(Task tr, boolean noAnimation, ActivityOptions options,
             AppTimeTracker timeTracker, String reason) {
         if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
 
         final ActivityStack topStack = getDisplay().getTopStack();
         final ActivityRecord topActivity = topStack != null ? topStack.getTopActivity() : null;
         final int numTasks = getChildCount();
-        final int index = mTaskHistory.indexOf(tr);
+        final int index = mChildren.indexOf(tr);
         if (numTasks == 0 || index < 0)  {
             // nothing to do!
             if (noAnimation) {
@@ -4176,13 +4032,13 @@
 
             // Shift all activities with this task up to the top
             // of the stack, keeping them in the same internal order.
-            insertTaskAtTop(tr, null);
+            positionChildAtTop(tr);
 
             // Don't refocus if invisible to current user
             final ActivityRecord top = tr.getTopActivity();
             if (top == null || !top.okToShowLocked()) {
                 if (top != null) {
-                    mStackSupervisor.mRecentTasks.add(top.getTaskRecord());
+                    mStackSupervisor.mRecentTasks.add(top.getTask());
                 }
                 ActivityOptions.abort(options);
                 return;
@@ -4235,7 +4091,7 @@
      * @return Returns true if the move completed, false if not.
      */
     final boolean moveTaskToBackLocked(int taskId) {
-        final TaskRecord tr = taskForIdLocked(taskId);
+        final Task tr = taskForIdLocked(taskId);
         if (tr == null) {
             Slog.i(TAG, "moveTaskToBack: bad taskId=" + taskId);
             return false;
@@ -4273,10 +4129,6 @@
 
         if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare to back transition: task=" + taskId);
 
-        mTaskHistory.remove(tr);
-        mTaskHistory.add(0, tr);
-        tr.updateTaskMovement(false);
-
         getDisplay().mDisplayContent.prepareAppTransition(TRANSIT_TASK_TO_BACK, false);
         moveToBack("moveTaskToBackLocked", tr);
 
@@ -4308,14 +4160,14 @@
             return;
         }
 
-        final TaskRecord startTask = start.getTaskRecord();
+        final Task startTask = start.getTask();
         boolean behindFullscreen = false;
         boolean updatedConfig = false;
 
-        for (int taskIndex = mTaskHistory.indexOf(startTask); taskIndex >= 0; --taskIndex) {
-            final TaskRecord task = getChildAt(taskIndex);
+        for (int taskIndex = mChildren.indexOf(startTask); taskIndex >= 0; --taskIndex) {
+            final Task task = getChildAt(taskIndex);
             final ArrayList<ActivityRecord> activities = task.mChildren;
-            int activityIndex = (start.getTaskRecord() == task)
+            int activityIndex = (start.getTask() == task)
                     ? activities.indexOf(start) : activities.size() - 1;
             for (; activityIndex >= 0; --activityIndex) {
                 final ActivityRecord r = activities.get(activityIndex);
@@ -4351,7 +4203,7 @@
             // Update override configurations of all tasks in the stack.
             final Rect taskBounds = tempTaskBounds != null ? tempTaskBounds : bounds;
             for (int i = getChildCount() - 1; i >= 0; i--) {
-                final TaskRecord task = getChildAt(i);
+                final Task task = getChildAt(i);
                 if (task.isResizeable()) {
                     if (tempTaskInsetBounds != null && !tempTaskInsetBounds.isEmpty()) {
                         task.setOverrideDisplayedBounds(taskBounds);
@@ -4375,12 +4227,6 @@
         }
     }
 
-    void onPipAnimationEndResize() {
-        if (mTaskStack == null) return;
-        mTaskStack.onPipAnimationEndResize();
-    }
-
-
     /**
      * Until we can break this "set task bounds to same as stack bounds" behavior, this
      * basically resizes both stack and task bounds to the same bounds.
@@ -4391,7 +4237,7 @@
         }
 
         for (int i = getChildCount() - 1; i >= 0; i--) {
-            final TaskRecord task = getChildAt(i);
+            final Task task = getChildAt(i);
             if (task.isResizeable()) {
                 task.setBounds(bounds);
             } else {
@@ -4407,7 +4253,7 @@
         }
 
         for (int i = getChildCount() - 1; i >= 0; i--) {
-            final TaskRecord task = getChildAt(i);
+            final Task task = getChildAt(i);
             if (bounds == null || bounds.isEmpty()) {
                 task.setOverrideDisplayedBounds(null);
             } else if (task.isResizeable()) {
@@ -4418,7 +4264,7 @@
 
     boolean willActivityBeVisibleLocked(IBinder token) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (r.appToken == token) {
@@ -4440,7 +4286,7 @@
 
     void closeSystemDialogsLocked() {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
@@ -4453,7 +4299,7 @@
     boolean finishDisabledPackageActivitiesLocked(String packageName, Set<String> filterByClasses,
             boolean doit, boolean evenPersistent, int userId) {
         boolean didSomething = false;
-        TaskRecord lastTask = null;
+        Task lastTask = null;
         ComponentName homeActivity = null;
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = getChildAt(taskNdx).mChildren;
@@ -4467,7 +4313,7 @@
                                 || filterByClasses.contains(r.mActivityComponent.getClassName())))
                         || (packageName == null && r.mUserId == userId);
                 if ((userId == UserHandle.USER_ALL || r.mUserId == userId)
-                        && (sameComponent || r.getTaskRecord() == lastTask)
+                        && (sameComponent || r.getTask() == lastTask)
                         && (r.app == null || evenPersistent || !r.app.isPersistent())) {
                     if (!doit) {
                         if (r.finishing) {
@@ -4487,7 +4333,7 @@
                     }
                     didSomething = true;
                     Slog.i(TAG, "  Force finishing activity " + r);
-                    lastTask = r.getTaskRecord();
+                    lastTask = r.getTask();
                     r.finishIfPossible("force-stop", true);
                 }
             }
@@ -4500,14 +4346,14 @@
      *         If {@param ignoreActivityType} or {@param ignoreWindowingMode} are not undefined,
      *         then skip running tasks that match those types.
      */
-    void getRunningTasks(List<TaskRecord> tasksOut, @ActivityType int ignoreActivityType,
+    void getRunningTasks(List<Task> tasksOut, @ActivityType int ignoreActivityType,
             @WindowingMode int ignoreWindowingMode, int callingUid, boolean allowed,
             boolean crossUser, ArraySet<Integer> profileIds) {
         boolean focusedStack = mRootActivityContainer.getTopDisplayFocusedStack() == this;
         boolean topTask = true;
         int userId = UserHandle.getUserId(callingUid);
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             if (task.getTopActivity() == null) {
                 // Skip if there are no activities in the task
                 continue;
@@ -4549,7 +4395,7 @@
         final int top = getChildCount() - 1;
         if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Performing unhandledBack(): top activity at " + top);
         if (top >= 0) {
-            final TaskRecord task = getChildAt(top);
+            final Task task = getChildAt(top);
             int activityTop = task.getChildCount() - 1;
             if (activityTop >= 0) {
                 task.getChildAt(activityTop).finishIfPossible("unhandled-back", true /* oomAdj */);
@@ -4578,7 +4424,7 @@
 
     void handleAppCrash(WindowProcessController app) {
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = task.getChildAt(activityNdx);
                 if (r.app == app) {
@@ -4605,7 +4451,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);
 
@@ -4643,7 +4489,7 @@
         }
         final String prefix = "    ";
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             if (needSep) {
                 pw.println("");
             }
@@ -4670,7 +4516,7 @@
         } else if ("top".equals(name)) {
             final int top = getChildCount() - 1;
             if (top >= 0) {
-                final TaskRecord task = getChildAt(top);
+                final Task task = getChildAt(top);
                 int listTop = task.getChildCount() - 1;
                 if (listTop >= 0) {
                     activities.add(task.getChildAt(listTop));
@@ -4681,7 +4527,7 @@
             matcher.build(name);
 
             for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-                final TaskRecord task = getChildAt(taskNdx);
+                final Task task = getChildAt(taskNdx);
                 for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                     final ActivityRecord r1 = task.getChildAt(activityNdx);
                     if (matcher.match(r1, r1.intent.getComponent())) {
@@ -4700,7 +4546,7 @@
         // All activities that came from the package must be
         // restarted as if there was a config change.
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
+            final Task task = getChildAt(taskNdx);
             for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord a = task.getChildAt(activityNdx);
                 if (a.info.packageName.equals(packageName)) {
@@ -4715,16 +4561,26 @@
         return starting;
     }
 
-    // TODO(stack-unify): Merge into removeChild method below.
-    void onChildRemoved(TaskRecord child, DisplayContent dc) {
-        mTaskHistory.remove(child);
-        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
-
-        ActivityDisplay display = getDisplay();
-        if (display == null && dc != null) {
-            display = dc.mActivityDisplay;
+    /**
+     * Removes the input task from this stack.
+     *
+     * @param child to remove.
+     * @param reason for removal.
+     */
+    void removeChild(Task child, String reason) {
+        if (!mChildren.contains(child)) {
+            // Not really in this stack anymore...
+            return;
         }
 
+        final ActivityDisplay display = getDisplay();
+        final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
+        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + child);
+
+        super.removeChild(child);
+
+        EventLog.writeEvent(EventLogTags.AM_REMOVE_TASK, child.mTaskId, mStackId);
+
         if (display.isSingleTaskInstance()) {
             mService.notifySingleTaskDisplayEmpty(display.mDisplayId);
         }
@@ -4733,21 +4589,15 @@
 
         if (!hasChild()) {
             // Stack is now empty...
-            remove();
+          removeIfPossible();
         }
+
+        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
     }
 
-    /**
-     * Removes the input task from this stack.
-     *
-     * @param task to remove.
-     * @param reason for removal.
-     */
-    void removeChild(TaskRecord task, String reason) {
-        final ActivityDisplay display = getDisplay();
-        final boolean topFocused = mRootActivityContainer.isTopDisplayFocusedStack(this);
-        mTaskStack.removeChild(task);
-        moveHomeStackToFrontIfNeeded(topFocused, display, reason);
+    @Override
+    void removeChild(Task task) {
+        removeChild(task, "removeChild");
     }
 
     void moveHomeStackToFrontIfNeeded(
@@ -4762,18 +4612,18 @@
         }
     }
 
-    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+    Task createTask(int taskId, ActivityInfo info, Intent intent,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop) {
-        return createTaskRecord(taskId, info, intent, voiceSession, voiceInteractor, toTop,
+        return createTask(taskId, info, intent, voiceSession, voiceInteractor, toTop,
                 null /*activity*/, null /*source*/, null /*options*/);
     }
 
-    TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
+    Task createTask(int taskId, ActivityInfo info, Intent intent,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean toTop, ActivityRecord activity, ActivityRecord source,
             ActivityOptions options) {
-        final TaskRecord task = TaskRecord.create(
+        final Task task = Task.create(
                 mService, taskId, info, intent, voiceSession, voiceInteractor, this);
         // add the task to stack first, mTaskPositioner might need the stack association
         addChild(task, toTop, (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0);
@@ -4788,39 +4638,21 @@
         return task;
     }
 
-    ArrayList<TaskRecord> getAllTasks() {
-        return new ArrayList<>(mTaskHistory);
+    ArrayList<Task> getAllTasks() {
+        return new ArrayList<>(mChildren);
     }
 
-    // TODO(stack-unify): Merge with addChild below.
-    void onChildAdded(TaskRecord task, int position) {
-        final boolean toTop = position >= getChildCount();
-        mTaskHistory.add(position, task);
-
-        // TODO: Feels like this should go in TaskRecord#onParentChanged
-        task.updateTaskMovement(toTop);
-    }
-
-    void addChild(final TaskRecord task, final boolean toTop, boolean showForAllUsers) {
+    void addChild(final Task task, final boolean toTop, boolean showForAllUsers) {
         if (isSingleTaskInstance() && hasChild()) {
             throw new IllegalStateException("Can only have one child on stack=" + this);
         }
 
-        final int position =
-                getAdjustedPositionForTask(task, toTop ? MAX_VALUE : 0, null /* starting */);
-
         // We only want to move the parents to the parents if we are creating this task at the
         // top of its stack.
-        mTaskStack.addChild(task, position, showForAllUsers, toTop /*moveParents*/);
-
-        if (toTop) {
-            // TODO: figure-out a way to remove this call.
-            positionChildWindowContainerAtTop(task);
-        }
+        addChild(task, toTop ? MAX_VALUE : 0, showForAllUsers, toTop /*moveParents*/);
     }
 
-    void positionChildAt(TaskRecord task, int index) {
-
+    void positionChildAt(Task task, int position) {
         if (task.getStack() != this) {
             throw new IllegalArgumentException("AS.positionChildAt: task=" + task
                     + " is not a child of stack=" + this + " current parent=" + task.getStack());
@@ -4830,7 +4662,20 @@
 
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
-        insertTaskAtPosition(task, index);
+
+        boolean toTop = position >= getChildCount();
+        boolean includingParents = toTop || getDisplay().getNextFocusableStack(this,
+                true /* ignoreCurrent */) == null;
+        if (WindowManagerDebugConfig.DEBUG_STACK) {
+            Slog.i(TAG_WM, "positionChildAt: positioning task=" + task + " at " + position);
+        }
+        positionChildAt(position, task, includingParents);
+        task.updateTaskMovement(toTop);
+        if (getDisplayContent().mAppTransition.isTransitionSet()) {
+            task.setSendingToBottom(!toTop);
+        }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+
 
         // TODO: Investigate if this random code is really needed.
         if (task.voiceSession != null) {
@@ -4869,7 +4714,7 @@
         display.positionChildAtTop(this, false /* includingParents */);
     }
 
-    /** NOTE: Should only be called from {@link TaskRecord#reparent}. */
+    /** NOTE: Should only be called from {@link Task#reparent}. */
     void moveToFrontAndResumeStateIfNeeded(ActivityRecord r, boolean moveToFront, boolean setResume,
             boolean setPause, String reason) {
         if (!moveToFront) {
@@ -4882,7 +4727,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) {
@@ -4898,7 +4743,7 @@
         }
     }
 
-    void animateResizePinnedStack(Rect sourceHintBounds, Rect toBounds, int animationDuration,
+    void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds, int animationDuration,
             boolean fromFullscreen) {
         if (!inPinnedWindowingMode()) return;
         if (toBounds == null /* toFullscreen */) {
@@ -4912,9 +4757,66 @@
                 return;
             }
         }
-        if (getTaskStack() == null) return;
-        getTaskStack().animateResizePinnedStack(toBounds, sourceHintBounds,
-                animationDuration, fromFullscreen);
+
+        // Get the from-bounds
+        final Rect fromBounds = new Rect();
+        getBounds(fromBounds);
+
+        // Get non-null fullscreen to-bounds for animating if the bounds are null
+        @BoundsAnimationController.SchedulePipModeChangedState int schedulePipModeChangedState =
+                NO_PIP_MODE_CHANGED_CALLBACKS;
+        final boolean toFullscreen = toBounds == null;
+        if (toFullscreen) {
+            if (fromFullscreen) {
+                throw new IllegalArgumentException("Should not defer scheduling PiP mode"
+                        + " change on animation to fullscreen.");
+            }
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
+
+            mWmService.getStackBounds(
+                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
+            if (!mTmpToBounds.isEmpty()) {
+                // If there is a fullscreen bounds, use that
+                toBounds = new Rect(mTmpToBounds);
+            } else {
+                // Otherwise, use the display bounds
+                toBounds = new Rect();
+                getDisplayContent().getBounds(toBounds);
+            }
+        } else if (fromFullscreen) {
+            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
+        }
+
+        setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
+
+        final Rect finalToBounds = toBounds;
+        final @BoundsAnimationController.SchedulePipModeChangedState int
+                finalSchedulePipModeChangedState = schedulePipModeChangedState;
+        final DisplayContent displayContent = getDisplayContent();
+        @BoundsAnimationController.AnimationType int intendedAnimationType =
+                displayContent.mBoundsAnimationController.getAnimationType();
+        if (intendedAnimationType == FADE_IN) {
+            if (fromFullscreen) {
+                setPinnedStackAlpha(0f);
+            }
+            if (toBounds.width() == fromBounds.width()
+                    && toBounds.height() == fromBounds.height()) {
+                intendedAnimationType = BoundsAnimationController.BOUNDS;
+            } else if (!fromFullscreen && !toBounds.equals(fromBounds)) {
+                // intendedAnimationType may have been reset at the end of RecentsAnimation,
+                // force it to BOUNDS type if we know for certain we're animating to
+                // a different bounds, especially for expand and collapse of PiP window.
+                intendedAnimationType = BoundsAnimationController.BOUNDS;
+            }
+        }
+
+        final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
+        mCancelCurrentBoundsAnimation = false;
+        displayContent.mBoundsAnimationController.getHandler().post(() -> {
+            displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
+                    finalToBounds, animationDuration, finalSchedulePipModeChangedState,
+                    fromFullscreen, toFullscreen, animationType);
+        });
     }
 
     void dismissPip() {
@@ -4927,14 +4829,18 @@
                     "Can't exit pinned mode if it's not pinned already.");
         }
 
-        final ArrayList<TaskRecord> tasks = getAllTasks();
-
-        if (tasks.size() != 1) {
+        if (mChildren.size() != 1) {
             throw new RuntimeException("There should be only one task in a pinned stack.");
         }
 
+        // give pinned stack a chance to save current bounds, this should happen before reparent.
+        final ActivityRecord top = topRunningNonOverlayTaskActivity();
+        if (top != null && top.isVisible()) {
+            top.savePinnedStackBounds();
+        }
+
         mWindowManager.inSurfaceTransaction(() -> {
-            final TaskRecord task = tasks.get(0);
+            final Task task = mChildren.get(0);
             setWindowingMode(WINDOWING_MODE_UNDEFINED);
 
             getDisplay().positionChildAtTop(this, false /* includingParents */);
@@ -4945,48 +4851,18 @@
         });
     }
 
-    /**
-     * Get current bounds of this stack, return empty when it is unavailable.
-     * @see TaskStack#getAnimationOrCurrentBounds(Rect)
-     */
-    void getAnimationOrCurrentBounds(Rect outBounds) {
-        final TaskStack stack = getTaskStack();
-        if (stack == null) {
-            outBounds.setEmpty();
-            return;
-        }
-        stack.getAnimationOrCurrentBounds(outBounds);
-    }
-
-    void setPictureInPictureAspectRatio(float aspectRatio) {
-        if (getTaskStack() == null) return;
-        getTaskStack().setPictureInPictureAspectRatio(aspectRatio);
-    }
-
-    void setPictureInPictureActions(List<RemoteAction> actions) {
-        if (getTaskStack() == null) return;
-        getTaskStack().setPictureInPictureActions(actions);
-    }
-
-    boolean isAnimatingBoundsToFullscreen() {
-        if (getTaskStack() == null) return false;
-        return getTaskStack().isAnimatingBoundsToFullscreen();
-    }
-
-    public void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
+    void updatePictureInPictureModeForPinnedStackAnimation(Rect targetStackBounds,
             boolean forceUpdate) {
         // It is guaranteed that the activities requiring the update will be in the pinned stack at
         // this point (either reparented before the animation into PiP, or before reparenting after
         // the animation out of PiP)
-        synchronized (mService.mGlobalLock) {
-            if (!isAttached()) {
-                return;
-            }
-            ArrayList<TaskRecord> tasks = getAllTasks();
-            for (int i = 0; i < tasks.size(); i++) {
-                mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
-                        forceUpdate);
-            }
+        if (!isAttached()) {
+            return;
+        }
+        ArrayList<Task> tasks = getAllTasks();
+        for (int i = 0; i < tasks.size(); i++) {
+            mStackSupervisor.updatePictureInPictureMode(tasks.get(i), targetStackBounds,
+                    forceUpdate);
         }
     }
 
@@ -4994,6 +4870,1580 @@
         return mStackId;
     }
 
+    Task findHomeTask() {
+        if (!isActivityTypeHome() || mChildren.isEmpty()) {
+            return null;
+        }
+        return mChildren.get(mChildren.size() - 1);
+    }
+
+    void prepareFreezingTaskBounds() {
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
+            task.prepareFreezingBounds();
+        }
+    }
+
+    /**
+     * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
+     * the normal task bounds.
+     *
+     * @param bounds The adjusted bounds.
+     */
+    private void setAdjustedBounds(Rect bounds) {
+        if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
+            return;
+        }
+
+        mAdjustedBounds.set(bounds);
+        final boolean adjusted = !mAdjustedBounds.isEmpty();
+        Rect insetBounds = null;
+        if (adjusted && isAdjustedForMinimizedDockedStack()) {
+            insetBounds = getRawBounds();
+        } else if (adjusted && mAdjustedForIme) {
+            if (mImeGoingAway) {
+                insetBounds = getRawBounds();
+            } else {
+                insetBounds = mFullyAdjustedImeBounds;
+            }
+        }
+        alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds);
+        mDisplayContent.setLayoutNeeded();
+
+        updateSurfaceBounds();
+    }
+
+    private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
+        if (matchParentBounds()) {
+            return;
+        }
+
+        final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
+
+        // Update bounds of containing tasks.
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mChildren.get(taskNdx);
+            task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
+        }
+    }
+
+    @Override
+    public int setBounds(Rect bounds) {
+        return setBounds(getRequestedOverrideBounds(), bounds);
+    }
+
+    private int setBounds(Rect existing, Rect bounds) {
+        if (equivalentBounds(existing, bounds)) {
+            return BOUNDS_CHANGE_NONE;
+        }
+
+        final int result = super.setBounds(!inMultiWindowMode() ? null : bounds);
+
+        updateAdjustedBounds();
+
+        updateSurfaceBounds();
+        return result;
+    }
+
+    /** Bounds of the stack without adjusting for other factors in the system like visibility
+     * of docked stack.
+     * Most callers should be using {@link ConfigurationContainer#getRequestedOverrideBounds} a
+     * it takes into consideration other system factors. */
+    void getRawBounds(Rect out) {
+        out.set(getRawBounds());
+    }
+
+    private Rect getRawBounds() {
+        return super.getBounds();
+    }
+
+    @Override
+    public void getBounds(Rect bounds) {
+        bounds.set(getBounds());
+    }
+
+    @Override
+    public Rect getBounds() {
+        // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
+        // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
+        // stack is visible since it is already what we want to represent to the rest of the
+        // system.
+        if (!mAdjustedBounds.isEmpty()) {
+            return mAdjustedBounds;
+        } else {
+            return super.getBounds();
+        }
+    }
+
+    /**
+     * Sets the bounds animation target bounds ahead of an animation.  This can't currently be done
+     * in onAnimationStart() since that is started on the UiThread.
+     */
+    private void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds,
+            boolean toFullscreen) {
+        if (mAnimationType == BoundsAnimationController.BOUNDS) {
+            mBoundsAnimatingRequested = true;
+        }
+        mBoundsAnimatingToFullscreen = toFullscreen;
+        if (destBounds != null) {
+            mBoundsAnimationTarget.set(destBounds);
+        } else {
+            mBoundsAnimationTarget.setEmpty();
+        }
+        if (sourceHintBounds != null) {
+            mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
+        } else if (!mBoundsAnimating) {
+            // If the bounds are already animating, we don't want to reset the source hint. This is
+            // because the source hint is sent when starting the animation from the client that
+            // requested to enter pip. Other requests can adjust the pip bounds during an animation,
+            // but could accidentally reset the source hint bounds.
+            mBoundsAnimationSourceHintBounds.setEmpty();
+        }
+
+        mPreAnimationBounds.set(getRawBounds());
+    }
+
+    /**
+     * @return the final bounds for the bounds animation.
+     */
+    void getFinalAnimationBounds(Rect outBounds) {
+        outBounds.set(mBoundsAnimationTarget);
+    }
+
+    /**
+     * @return the final source bounds for the bounds animation.
+     */
+    void getFinalAnimationSourceHintBounds(Rect outBounds) {
+        outBounds.set(mBoundsAnimationSourceHintBounds);
+    }
+
+    /**
+     * @return the final animation bounds if the task stack is currently being animated, or the
+     *         current stack bounds otherwise.
+     */
+    void getAnimationOrCurrentBounds(Rect outBounds) {
+        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
+            getFinalAnimationBounds(outBounds);
+            return;
+        }
+        getBounds(outBounds);
+    }
+
+    /** Bounds of the stack with other system factors taken into consideration. */
+    void getDimBounds(Rect out) {
+        getBounds(out);
+    }
+
+    /**
+     * Updates the passed-in {@code inOutBounds} based on the current state of the
+     * pinned controller. This gets run *after* the override configuration is updated, so it's
+     * safe to rely on the controller's state in here (though eventually this dependence should
+     * be removed).
+     *
+     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
+     * update pinned controller state.
+     *
+     * @param inOutBounds the bounds to update (both input and output).
+     * @return true if bounds were updated to some non-empty value.
+     */
+    boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
+        boolean animating = false;
+        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
+            animating = true;
+            getFinalAnimationBounds(mTmpRect2);
+        } else {
+            mTmpRect2.set(inOutBounds);
+        }
+        boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
+                mTmpRect2, mTmpRect3);
+        if (updated) {
+            inOutBounds.set(mTmpRect3);
+
+            // The final boundary is updated while there is an existing boundary animation. Let's
+            // cancel this animation to prevent the obsolete animation overwritten updated bounds.
+            if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
+                final DisplayContent displayContent = getDisplayContent();
+                displayContent.mBoundsAnimationController.getHandler().post(() ->
+                        displayContent.mBoundsAnimationController.cancel(this));
+            }
+            // Once we've set the bounds based on the rotation of the old bounds in the new
+            // orientation, clear the animation target bounds since they are obsolete, and
+            // cancel any currently running animations
+            mBoundsAnimationTarget.setEmpty();
+            mBoundsAnimationSourceHintBounds.setEmpty();
+            mCancelCurrentBoundsAnimation = true;
+        }
+        return updated;
+    }
+
+    /**
+     * Updates the passed-in {@code inOutBounds} based on the current state of the
+     * docked controller. This gets run *after* the override configuration is updated, so it's
+     * safe to rely on the controller's state in here (though eventually this dependence should
+     * be removed).
+     *
+     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
+     * update docked controller state.
+     *
+     * @param parentConfig the parent configuration for reference.
+     * @param inOutBounds the bounds to update (both input and output).
+     */
+    void calculateDockedBoundsForConfigChange(Configuration parentConfig, Rect inOutBounds) {
+        final boolean primary =
+                getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+        repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds);
+        final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout;
+        snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds);
+        if (primary) {
+            final int newDockSide = getDockSide(parentConfig, inOutBounds);
+            // Update the dock create mode and clear the dock create bounds, these
+            // might change after a rotation and the original values will be invalid.
+            mWmService.setDockedStackCreateStateLocked(
+                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
+                            ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
+                            : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
+                    null);
+            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
+        }
+    }
+
+    /**
+     * Some primary split screen sides are not allowed by the policy. This method queries the policy
+     * and moves the primary stack around if needed.
+     *
+     * @param parentConfig the configuration of the stack's parent.
+     * @param primary true if adjusting the primary docked stack, false for secondary.
+     * @param inOutBounds the bounds of the stack to adjust.
+     */
+    void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary,
+            Rect inOutBounds) {
+        final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
+        final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide);
+        final int primaryDockSide = primary ? dockSide : otherDockSide;
+        if (mDisplayContent.getDockedDividerController()
+                .canPrimaryStackDockTo(primaryDockSide,
+                        parentConfig.windowConfiguration.getBounds(),
+                        parentConfig.windowConfiguration.getRotation())) {
+            return;
+        }
+        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
+        switch (otherDockSide) {
+            case DOCKED_LEFT:
+                int movement = inOutBounds.left;
+                inOutBounds.left -= movement;
+                inOutBounds.right -= movement;
+                break;
+            case DOCKED_RIGHT:
+                movement = parentBounds.right - inOutBounds.right;
+                inOutBounds.left += movement;
+                inOutBounds.right += movement;
+                break;
+            case DOCKED_TOP:
+                movement = inOutBounds.top;
+                inOutBounds.top -= movement;
+                inOutBounds.bottom -= movement;
+                break;
+            case DOCKED_BOTTOM:
+                movement = parentBounds.bottom - inOutBounds.bottom;
+                inOutBounds.top += movement;
+                inOutBounds.bottom += movement;
+                break;
+        }
+    }
+
+    /**
+     * Snaps the bounds after rotation to the closest snap target for the docked stack.
+     */
+    void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout,
+            Rect outBounds) {
+
+        // Calculate the current position.
+        final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
+        final int dockSide = getDockSide(parentConfig, outBounds);
+        final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
+                dockSide, dividerSize);
+        final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
+        final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
+
+        // Snap the position to a target.
+        final int rotation = parentConfig.windowConfiguration.getRotation();
+        final int orientation = parentConfig.orientation;
+        mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, displayWidth, displayHeight,
+                displayCutout, outBounds);
+        final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
+                mWmService.mContext.getResources(), displayWidth, displayHeight,
+                dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
+                getDockSide(), isMinimizedDockAndHomeStackResizable());
+        final DividerSnapAlgorithm.SnapTarget target =
+                algorithm.calculateNonDismissingSnapTarget(dividerPosition);
+
+        // Recalculate the bounds based on the position of the target.
+        DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
+                outBounds, displayWidth, displayHeight,
+                dividerSize);
+    }
+
+    /**
+     * Put a Task in this stack. Used for adding only.
+     * When task is added to top of the stack, the entire branch of the hierarchy (including stack
+     * and display) will be brought to top.
+     * @param task The task to add.
+     * @param position Target position to add the task to.
+     * @param showForAllUsers Whether to show the task regardless of the current user.
+     */
+    void addChild(Task task, int position, boolean showForAllUsers, boolean moveParents) {
+        // Add child task.
+        addChild(task, null);
+
+        // Move child to a proper position, as some restriction for position might apply.
+        position = positionChildAt(
+                position, task, moveParents /* includingParents */, showForAllUsers);
+    }
+
+    @Override
+    void addChild(Task task, int position) {
+        addChild(task, position, task.showForAllUsers(), false /* includingParents */);
+    }
+
+    void positionChildAtTop(Task child) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_TOP, child, true /* includingParents */);
+        child.updateTaskMovement(true);
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent.mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(false);
+        }
+        displayContent.layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    private void positionChildAtBottom(Task child) {
+        // If there are other focusable stacks on the display, the z-order of the display should not
+        // be changed just because a task was placed at the bottom. E.g. if it is moving the topmost
+        // task to bottom, the next focusable stack on the same display should be focused.
+        final ActivityStack nextFocusableStack = getDisplay().getNextFocusableStack(
+                child.getStack(), true /* ignoreCurrent */);
+        positionChildAtBottom(child, nextFocusableStack == null /* includingParents */);
+        child.updateTaskMovement(true);
+    }
+
+    @VisibleForTesting
+    void positionChildAtBottom(Task child, boolean includingParents) {
+        if (child == null) {
+            // TODO: Fix the call-points that cause this to happen.
+            return;
+        }
+
+        positionChildAt(POSITION_BOTTOM, child, includingParents);
+
+        if (getDisplayContent().mAppTransition.isTransitionSet()) {
+            child.setSendingToBottom(true);
+        }
+        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+    }
+
+    @Override
+    void positionChildAt(int position, Task child, boolean includingParents) {
+        positionChildAt(position, child, includingParents, child.showForAllUsers());
+    }
+
+    /**
+     * Overridden version of {@link ActivityStack#positionChildAt(int, Task, boolean)}. Used in
+     * {@link ActivityStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can
+     * receive showForAllUsers param from {@link ActivityRecord} instead of
+     * {@link Task#showForAllUsers()}.
+     */
+    private int positionChildAt(int position, Task child, boolean includingParents,
+            boolean showForAllUsers) {
+        final int targetPosition = findPositionForTask(child, position, showForAllUsers);
+        super.positionChildAt(targetPosition, child, includingParents);
+
+        // Log positioning.
+        if (DEBUG_TASK_MOVEMENT) {
+            Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position);
+        }
+
+        final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
+        EventLog.writeEvent(com.android.server.EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop,
+                targetPosition);
+
+        return targetPosition;
+    }
+
+    @Override
+    void onChildPositionChanged(WindowContainer child) {
+        if (!mChildren.contains(child)) {
+            return;
+        }
+
+        final Task task = (Task) child;
+        final boolean isTop = getTopChild() == task;
+        task.updateTaskMovement(isTop);
+        if (isTop) {
+            final DisplayContent displayContent = getDisplayContent();
+            if (displayContent.mAppTransition.isTransitionSet()) {
+                task.setSendingToBottom(false);
+            }
+            displayContent.layoutAndAssignWindowLayersIfNeeded();
+        }
+    }
+
+    // TODO(display-unify): Remove after display unification.
+    protected void onParentChanged(ActivityDisplay newParent, ActivityDisplay oldParent) {
+        onParentChanged(
+                newParent != null ? newParent.mDisplayContent : null,
+                oldParent != null ? oldParent.mDisplayContent : null);
+    }
+
+    @Override
+    protected void onParentChanged(
+            ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        final ActivityDisplay display = newParent != null
+                ? ((WindowContainer) newParent).getDisplayContent().mActivityDisplay : null;
+        final ActivityDisplay oldDisplay = oldParent != null
+                ? ((WindowContainer) oldParent).getDisplayContent().mActivityDisplay : null;
+
+        mDisplayId = (display != null) ? display.mDisplayId : INVALID_DISPLAY;
+        mPrevDisplayId = (oldDisplay != null) ? oldDisplay.mDisplayId : INVALID_DISPLAY;
+
+        if (display != null) {
+            // Rotations are relative to the display. This means if there are 2 displays rotated
+            // differently (eg. 2 monitors with one landscape and one portrait), moving a stack
+            // from one to the other could look like a rotation change. To prevent this
+            // apparent rotation change (and corresponding bounds rotation), pretend like our
+            // current rotation is already the same as the new display.
+            // Note, if ActivityStack or related logic ever gets nested, this logic will need
+            // to move to onConfigurationChanged.
+            getConfiguration().windowConfiguration.setRotation(
+                    display.getWindowConfiguration().getRotation());
+        }
+        super.onParentChanged(newParent, oldParent);
+        if (getParent() == null && mDisplayContent != null) {
+            EventLog.writeEvent(com.android.server.EventLogTags.WM_STACK_REMOVED, mStackId);
+
+            mDisplayContent = null;
+            mWmService.mWindowPlacerLocked.requestTraversal();
+        }
+        if (display != null && inSplitScreenPrimaryWindowingMode()) {
+            // If we created a docked stack we want to resize it so it resizes all other stacks
+            // in the system.
+            getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
+                    mTmpRect /* outStackBounds */, mTmpRect2 /* outTempTaskBounds */);
+            mStackSupervisor.resizeDockedStackLocked(getRequestedOverrideBounds(), mTmpRect,
+                    mTmpRect2, null, null, PRESERVE_WINDOWS);
+        }
+        mRootActivityContainer.updateUIDsPresentOnDisplay();
+
+        // Resume next focusable stack after reparenting to another display if we aren't removing
+        // the prevous display.
+        if (oldDisplay != null && oldDisplay.isRemoving()) {
+            postReparent();
+        }
+    }
+
+    void reparent(DisplayContent newParent, boolean onTop) {
+        // Real parent of stack is within display object, so we have to delegate re-parenting there.
+        newParent.moveStackToDisplay(this, onTop);
+    }
+
+    // TODO: We should really have users as a window container in the hierarchy so that we don't
+    // have to do complicated things like we are doing in this method.
+    int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) {
+        final boolean canShowTask =
+                showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId);
+
+        final int stackSize = mChildren.size();
+        int minPosition = 0;
+        int maxPosition = stackSize - 1;
+
+        if (canShowTask) {
+            minPosition = computeMinPosition(minPosition, stackSize);
+        } else {
+            maxPosition = computeMaxPosition(maxPosition);
+        }
+
+        // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
+        if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
+            return POSITION_BOTTOM;
+        } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) {
+            return POSITION_TOP;
+        }
+        // Reset position based on minimum/maximum possible positions.
+        return Math.min(Math.max(targetPosition, minPosition), maxPosition);
+    }
+
+    /** Calculate the minimum possible position for a task that can be shown to the user.
+     *  The minimum position will be above all other tasks that can't be shown.
+     *  @param minPosition The minimum position the caller is suggesting.
+     *                  We will start adjusting up from here.
+     *  @param size The size of the current task list.
+     */
+    private int computeMinPosition(int minPosition, int size) {
+        while (minPosition < size) {
+            final Task tmpTask = mChildren.get(minPosition);
+            final boolean canShowTmpTask =
+                    tmpTask.showForAllUsers()
+                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
+            if (canShowTmpTask) {
+                break;
+            }
+            minPosition++;
+        }
+        return minPosition;
+    }
+
+    /** Calculate the maximum possible position for a task that can't be shown to the user.
+     *  The maximum position will be below all other tasks that can be shown.
+     *  @param maxPosition The maximum position the caller is suggesting.
+     *                  We will start adjusting down from here.
+     */
+    private int computeMaxPosition(int maxPosition) {
+        while (maxPosition > 0) {
+            final Task tmpTask = mChildren.get(maxPosition);
+            final boolean canShowTmpTask =
+                    tmpTask.showForAllUsers()
+                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
+            if (!canShowTmpTask) {
+                break;
+            }
+            maxPosition--;
+        }
+        return maxPosition;
+    }
+
+    private void updateSurfaceBounds() {
+        updateSurfaceSize(getPendingTransaction());
+        updateSurfacePosition();
+        scheduleAnimation();
+    }
+
+    /**
+     * Calculate an amount by which to expand the stack bounds in each direction.
+     * Used to make room for shadows in the pinned windowing mode.
+     */
+    int getStackOutset() {
+        DisplayContent displayContent = getDisplayContent();
+        if (inPinnedWindowingMode() && displayContent != null) {
+            final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
+
+            // We multiply by two to match the client logic for converting view elevation
+            // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
+            return (int) Math.ceil(
+                    mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, displayMetrics)
+                            * 2);
+        }
+        return 0;
+    }
+
+    @Override
+    void getRelativeDisplayedPosition(Point outPos) {
+        super.getRelativeDisplayedPosition(outPos);
+        final int outset = getStackOutset();
+        outPos.x -= outset;
+        outPos.y -= outset;
+    }
+
+    private void updateSurfaceSize(SurfaceControl.Transaction transaction) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+
+        final Rect stackBounds = getDisplayedBounds();
+        int width = stackBounds.width();
+        int height = stackBounds.height();
+
+        final int outset = getStackOutset();
+        width += 2 * outset;
+        height += 2 * outset;
+
+        if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
+            return;
+        }
+        transaction.setWindowCrop(mSurfaceControl, width, height);
+        mLastSurfaceSize.set(width, height);
+    }
+
+    @VisibleForTesting
+    Point getLastSurfaceSize() {
+        return mLastSurfaceSize;
+    }
+
+    @Override
+    void onDisplayChanged(DisplayContent dc) {
+        super.onDisplayChanged(dc);
+        updateSurfaceBounds();
+    }
+
+    /**
+     * Determines the stack and task bounds of the other stack when in docked mode. The current task
+     * bounds is passed in but depending on the stack, the task and stack must match. Only in
+     * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds
+     * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds
+     * is calculated and is also used for its task bounds.
+     * If any of the out bounds are empty, it represents default bounds
+     *
+     * @param currentTempTaskBounds the current task bounds of the other stack
+     * @param outStackBounds the calculated stack bounds of the other stack
+     * @param outTempTaskBounds the calculated task bounds of the other stack
+     */
+    void getStackDockedModeBounds(Rect dockedBounds,
+            Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) {
+        final Configuration parentConfig = getParent().getConfiguration();
+        outTempTaskBounds.setEmpty();
+
+        if (dockedBounds == null || dockedBounds.isEmpty()) {
+            // Calculate the primary docked bounds.
+            final boolean dockedOnTopOrLeft = mWmService.mDockedStackCreateMode
+                    == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
+            getStackDockedModeBounds(parentConfig,
+                    true /* primary */, outStackBounds, dockedBounds,
+                    mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
+            return;
+        }
+        final int dockedSide = getDockSide(parentConfig, dockedBounds);
+
+        // When the home stack is resizable, should always have the same stack and task bounds
+        if (isActivityTypeHome()) {
+            final Task homeTask = findHomeTask();
+            if (homeTask == null || homeTask.isResizeable()) {
+                // Calculate the home stack bounds when in docked mode and the home stack is
+                // resizeable.
+                getDisplayContent().mDividerControllerLocked
+                        .getHomeStackBoundsInDockedMode(parentConfig,
+                                dockedSide, outStackBounds);
+            } else {
+                // Home stack isn't resizeable, so don't specify stack bounds.
+                outStackBounds.setEmpty();
+            }
+
+            outTempTaskBounds.set(outStackBounds);
+            return;
+        }
+
+        // When minimized state, the stack bounds for all non-home and docked stack bounds should
+        // match the passed task bounds
+        if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) {
+            outStackBounds.set(currentTempTaskBounds);
+            return;
+        }
+
+        if (dockedSide == DOCKED_INVALID) {
+            // Not sure how you got here...Only thing we can do is return current bounds.
+            Slog.e(TAG_WM, "Failed to get valid docked side for docked stack");
+            outStackBounds.set(getRawBounds());
+            return;
+        }
+
+        final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
+        getStackDockedModeBounds(parentConfig,
+                false /* primary */, outStackBounds, dockedBounds,
+                mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
+    }
+
+    /**
+     * Outputs the bounds a stack should be given the presence of a docked stack on the display.
+     * @param parentConfig The parent configuration.
+     * @param primary {@code true} if getting the primary stack bounds.
+     * @param outBounds Output bounds that should be used for the stack.
+     * @param dockedBounds Bounds of the docked stack.
+     * @param dockDividerWidth We need to know the width of the divider make to the output bounds
+     *                         close to the side of the dock.
+     * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
+     */
+    private void getStackDockedModeBounds(Configuration parentConfig, boolean primary,
+            Rect outBounds, Rect dockedBounds, int dockDividerWidth,
+            boolean dockOnTopOrLeft) {
+        final Rect displayRect = parentConfig.windowConfiguration.getBounds();
+        final boolean splitHorizontally = displayRect.width() > displayRect.height();
+
+        outBounds.set(displayRect);
+        if (primary) {
+            if (mWmService.mDockedStackCreateBounds != null) {
+                outBounds.set(mWmService.mDockedStackCreateBounds);
+                return;
+            }
+
+            // The initial bounds of the docked stack when it is created about half the screen space
+            // and its bounds can be adjusted after that. The bounds of all other stacks are
+            // adjusted to occupy whatever screen space the docked stack isn't occupying.
+            final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
+            mDisplayContent.getDisplayPolicy().getStableInsetsLw(
+                    parentConfig.windowConfiguration.getRotation(),
+                    displayRect.width(), displayRect.height(), displayCutout, mTmpRect2);
+            final int position = new DividerSnapAlgorithm(mWmService.mContext.getResources(),
+                    displayRect.width(),
+                    displayRect.height(),
+                    dockDividerWidth,
+                    parentConfig.orientation == ORIENTATION_PORTRAIT,
+                    mTmpRect2).getMiddleTarget().position;
+
+            if (dockOnTopOrLeft) {
+                if (splitHorizontally) {
+                    outBounds.right = position;
+                } else {
+                    outBounds.bottom = position;
+                }
+            } else {
+                if (splitHorizontally) {
+                    outBounds.left = position + dockDividerWidth;
+                } else {
+                    outBounds.top = position + dockDividerWidth;
+                }
+            }
+            return;
+        }
+
+        // Other stacks occupy whatever space is left by the docked stack.
+        if (!dockOnTopOrLeft) {
+            if (splitHorizontally) {
+                outBounds.right = dockedBounds.left - dockDividerWidth;
+            } else {
+                outBounds.bottom = dockedBounds.top - dockDividerWidth;
+            }
+        } else {
+            if (splitHorizontally) {
+                outBounds.left = dockedBounds.right + dockDividerWidth;
+            } else {
+                outBounds.top = dockedBounds.bottom + dockDividerWidth;
+            }
+        }
+        DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
+    }
+
+    void resetDockedStackToMiddle() {
+        if (!inSplitScreenPrimaryWindowingMode()) {
+            throw new IllegalStateException("Not a docked stack=" + this);
+        }
+
+        mWmService.mDockedStackCreateBounds = null;
+
+        final Rect bounds = new Rect();
+        final Rect tempBounds = new Rect();
+        getStackDockedModeBounds(null /* dockedBounds */, null /* currentTempTaskBounds */,
+                bounds, tempBounds);
+        mStackSupervisor.resizeDockedStackLocked(bounds, null /* tempTaskBounds */,
+                null /* tempTaskInsetBounds */, null /* tempOtherTaskBounds */,
+                null /* tempOtherTaskInsetBounds */, false /* preserveWindows */,
+                false /* deferResume */);
+    }
+
+    @Override
+    void removeIfPossible() {
+        if (isAnimating(TRANSITION | CHILDREN)) {
+            mDeferRemoval = true;
+            return;
+        }
+        removeImmediately();
+    }
+
+    /**
+     * Adjusts the stack bounds if the IME is visible.
+     *
+     * @param imeWin The IME window.
+     * @param keepLastAmount Use {@code true} to keep the last adjusted amount from
+     *                       {@link DockedStackDividerController} for adjusting the stack bounds,
+     *                       Use {@code false} to reset adjusted amount as 0.
+     * @see #updateAdjustForIme(float, float, boolean)
+     */
+    void setAdjustedForIme(WindowState imeWin, boolean keepLastAmount) {
+        mImeWin = imeWin;
+        mImeGoingAway = false;
+        if (!mAdjustedForIme || keepLastAmount) {
+            mAdjustedForIme = true;
+            DockedStackDividerController controller = getDisplayContent().mDividerControllerLocked;
+            final float adjustImeAmount = keepLastAmount ? controller.mLastAnimationProgress : 0f;
+            final float adjustDividerAmount = keepLastAmount ? controller.mLastDividerProgress : 0f;
+            updateAdjustForIme(adjustImeAmount, adjustDividerAmount, true /* force */);
+        }
+    }
+
+    boolean isAdjustedForIme() {
+        return mAdjustedForIme;
+    }
+
+    boolean isAnimatingForIme() {
+        return mImeWin != null && mImeWin.isAnimatingLw();
+    }
+
+    /**
+     * Update the stack's bounds (crop or position) according to the IME window's
+     * current position. When IME window is animated, the bottom stack is animated
+     * together to track the IME window's current position, and the top stack is
+     * cropped as necessary.
+     *
+     * @return true if a traversal should be performed after the adjustment.
+     */
+    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
+        if (adjustAmount != mAdjustImeAmount
+                || adjustDividerAmount != mAdjustDividerAmount || force) {
+            mAdjustImeAmount = adjustAmount;
+            mAdjustDividerAmount = adjustDividerAmount;
+            updateAdjustedBounds();
+            return isVisible();
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Resets the adjustment after it got adjusted for the IME.
+     * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
+     *                        animations; otherwise, set flag and animates the window away together
+     *                        with IME window.
+     */
+    void resetAdjustedForIme(boolean adjustBoundsNow) {
+        if (adjustBoundsNow) {
+            mImeWin = null;
+            mImeGoingAway = false;
+            mAdjustImeAmount = 0f;
+            mAdjustDividerAmount = 0f;
+            if (!mAdjustedForIme) {
+                return;
+            }
+            mAdjustedForIme = false;
+            updateAdjustedBounds();
+            mWmService.setResizeDimLayer(false, getWindowingMode(), 1.0f);
+        } else {
+            mImeGoingAway |= mAdjustedForIme;
+        }
+    }
+
+    /**
+     * Sets the amount how much we currently minimize our stack.
+     *
+     * @param minimizeAmount The amount, between 0 and 1.
+     * @return Whether the amount has changed and a layout is needed.
+     */
+    boolean setAdjustedForMinimizedDock(float minimizeAmount) {
+        if (minimizeAmount != mMinimizeAmount) {
+            mMinimizeAmount = minimizeAmount;
+            updateAdjustedBounds();
+            return isVisible();
+        } else {
+            return false;
+        }
+    }
+
+    boolean shouldIgnoreInput() {
+        return isAdjustedForMinimizedDockedStack()
+                || (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable());
+    }
+
+    /**
+     * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
+     * to the list of to be drawn windows the service is waiting for.
+     */
+    void beginImeAdjustAnimation() {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final Task task = mChildren.get(j);
+            if (task.hasContentToDisplay()) {
+                task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+                task.setWaitingForDrawnIfResizingChanged();
+            }
+        }
+    }
+
+    /**
+     * Resets the resizing state of all windows.
+     */
+    void endImeAdjustAnimation() {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
+        }
+    }
+
+    int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
+        return displayContentRect.top + (int)
+                ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
+    }
+
+    private boolean adjustForIME(final WindowState imeWin) {
+        // To prevent task stack resize animation may flicking when playing app transition
+        // animation & IME window enter animation in parallel, we need to make sure app
+        // transition is done and then adjust task size for IME, skip the new adjusted frame when
+        // app transition is still running.
+        if (getDisplayContent().mAppTransition.isRunning()) {
+            return false;
+        }
+
+        final int dockedSide = getDockSide();
+        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
+        if (imeWin == null || !dockedTopOrBottom) {
+            return false;
+        }
+
+        final Rect displayStableRect = mTmpRect;
+        final Rect contentBounds = mTmpRect2;
+
+        // Calculate the content bounds excluding the area occupied by IME
+        getDisplayContent().getStableRect(displayStableRect);
+        contentBounds.set(displayStableRect);
+        int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
+
+        imeTop += imeWin.getGivenContentInsetsLw().top;
+        if (contentBounds.bottom > imeTop) {
+            contentBounds.bottom = imeTop;
+        }
+
+        final int yOffset = displayStableRect.bottom - contentBounds.bottom;
+
+        final int dividerWidth =
+                getDisplayContent().mDividerControllerLocked.getContentWidth();
+        final int dividerWidthInactive =
+                getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
+
+        if (dockedSide == DOCKED_TOP) {
+            // If this stack is docked on top, we make it smaller so the bottom stack is not
+            // occluded by IME. We shift its bottom up by the height of the IME, but
+            // leaves at least 30% of the top stack visible.
+            final int minTopStackBottom =
+                    getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
+            final int bottom = Math.max(
+                    getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
+                    minTopStackBottom);
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount)
+                    * getRawBounds().bottom);
+            mFullyAdjustedImeBounds.set(getRawBounds());
+        } else {
+            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
+            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
+
+            // When the stack is on bottom and has focus, it needs to be moved up so as to
+            // not occluded by IME, and at the same time adjusted for divider width.
+            // We try to move it up by the height of the IME window, but only to the extent
+            // that leaves at least 30% of the top stack visible.
+            // 'top' is where the top of bottom stack will move to in this case.
+            final int topBeforeImeAdjust =
+                    getRawBounds().top - dividerWidth + dividerWidthInactive;
+            final int minTopStackBottom =
+                    getMinTopStackBottom(displayStableRect,
+                            getRawBounds().top - dividerWidth);
+            final int top = Math.max(
+                    getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
+
+            mTmpAdjustedBounds.set(getRawBounds());
+            // Account for the adjustment for IME and divider width separately.
+            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
+            // and dividerWidthDelta is due to divider width change only.
+            mTmpAdjustedBounds.top =
+                    getRawBounds().top + (int) (mAdjustImeAmount * (top - topBeforeImeAdjust)
+                            + mAdjustDividerAmount * dividerWidthDelta);
+            mFullyAdjustedImeBounds.set(getRawBounds());
+            mFullyAdjustedImeBounds.top = top;
+            mFullyAdjustedImeBounds.bottom = top + getRawBounds().height();
+        }
+        return true;
+    }
+
+    private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
+        final int dockSide = getDockSide();
+        if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
+            return false;
+        }
+
+        if (dockSide == DOCKED_TOP) {
+            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
+            int topInset = mTmpRect.top;
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount)
+                    * getRawBounds().bottom);
+        } else if (dockSide == DOCKED_LEFT) {
+            mTmpAdjustedBounds.set(getRawBounds());
+            final int width = getRawBounds().width();
+            mTmpAdjustedBounds.right =
+                    (int) (minimizeAmount * mDockedStackMinimizeThickness
+                            + (1 - minimizeAmount) * getRawBounds().right);
+            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
+        } else if (dockSide == DOCKED_RIGHT) {
+            mTmpAdjustedBounds.set(getRawBounds());
+            mTmpAdjustedBounds.left =
+                    (int) (minimizeAmount * (getRawBounds().right - mDockedStackMinimizeThickness)
+                            + (1 - minimizeAmount) * getRawBounds().left);
+        }
+        return true;
+    }
+
+    private boolean isMinimizedDockAndHomeStackResizable() {
+        return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
+                && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
+    }
+
+    /**
+     * @return the distance in pixels how much the stack gets minimized from it's original size
+     */
+    int getMinimizeDistance() {
+        final int dockSide = getDockSide();
+        if (dockSide == DOCKED_INVALID) {
+            return 0;
+        }
+
+        if (dockSide == DOCKED_TOP) {
+            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
+            int topInset = mTmpRect.top;
+            return getRawBounds().bottom - topInset;
+        } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
+            return getRawBounds().width() - mDockedStackMinimizeThickness;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Updates the adjustment depending on it's current state.
+     */
+    private void updateAdjustedBounds() {
+        boolean adjust = false;
+        if (mMinimizeAmount != 0f) {
+            adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
+        } else if (mAdjustedForIme) {
+            adjust = adjustForIME(mImeWin);
+        }
+        if (!adjust) {
+            mTmpAdjustedBounds.setEmpty();
+        }
+        setAdjustedBounds(mTmpAdjustedBounds);
+
+        final boolean isImeTarget = (mWmService.getImeFocusStackLocked() == this);
+        if (mAdjustedForIme && adjust && !isImeTarget) {
+            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
+                    * IME_ADJUST_DIM_AMOUNT;
+            mWmService.setResizeDimLayer(true, getWindowingMode(), alpha);
+        }
+    }
+
+    void applyAdjustForImeIfNeeded(Task task) {
+        if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
+            return;
+        }
+
+        final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds;
+        task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
+        mDisplayContent.setLayoutNeeded();
+    }
+
+
+    boolean isAdjustedForMinimizedDockedStack() {
+        return mMinimizeAmount != 0f;
+    }
+
+    /**
+     * @return {@code true} if we have a {@link Task} that is animating (currently only used for the
+     *         recents animation); {@code false} otherwise.
+     */
+    boolean isTaskAnimating() {
+        for (int j = mChildren.size() - 1; j >= 0; j--) {
+            final Task task = mChildren.get(j);
+            if (task.isTaskAnimating()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        pw.println(prefix + "mStackId=" + mStackId);
+        pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
+        pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
+        if (mMinimizeAmount != 0f) {
+            pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
+        }
+        if (mAdjustedForIme) {
+            pw.println(prefix + "mAdjustedForIme=true");
+            pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
+            pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
+        }
+        if (!mAdjustedBounds.isEmpty()) {
+            pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
+        }
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
+            mChildren.get(taskNdx).dump(pw, prefix + "  ", dumpAll);
+        }
+        if (!mExitingActivities.isEmpty()) {
+            pw.println();
+            pw.println("  Exiting application tokens:");
+            for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
+                WindowToken token = mExitingActivities.get(i);
+                pw.print("  Exiting App #"); pw.print(i);
+                pw.print(' '); pw.print(token);
+                pw.println(':');
+                token.dump(pw, "    ", dumpAll);
+            }
+        }
+        mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix);
+    }
+
+    @Override
+    boolean fillsParent() {
+        return matchParentBounds();
+    }
+
+    String getName() {
+        return toShortString();
+    }
+
+    public String toShortString() {
+        return "Stack=" + mStackId;
+    }
+
+    /**
+     * For docked workspace (or workspace that's side-by-side to the docked), provides
+     * information which side of the screen was the dock anchored.
+     */
+    int getDockSide() {
+        return getDockSide(mDisplayContent.getConfiguration(), getRawBounds());
+    }
+
+    int getDockSideForDisplay(DisplayContent dc) {
+        return getDockSide(dc, dc.getConfiguration(), getRawBounds());
+    }
+
+    int getDockSide(Configuration parentConfig, Rect bounds) {
+        if (mDisplayContent == null) {
+            return DOCKED_INVALID;
+        }
+        return getDockSide(mDisplayContent, parentConfig, bounds);
+    }
+
+    private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) {
+        return dc.getDockedDividerController().getDockSide(bounds,
+                parentConfig.windowConfiguration.getBounds(),
+                parentConfig.orientation, parentConfig.windowConfiguration.getRotation());
+    }
+
+    boolean hasTaskForUser(int userId) {
+        for (int i = mChildren.size() - 1; i >= 0; i--) {
+            final Task task = mChildren.get(i);
+            if (task.mUserId == userId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void findTaskForResizePoint(int x, int y, int delta,
+            DisplayContent.TaskForResizePointSearchResult results) {
+        if (!getWindowConfiguration().canResizeTask()) {
+            results.searchDone = true;
+            return;
+        }
+
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+                results.searchDone = true;
+                return;
+            }
+
+            // We need to use the task's dim bounds (which is derived from the visible bounds of
+            // its apps windows) for any touch-related tests. Can't use the task's original
+            // bounds because it might be adjusted to fit the content frame. One example is when
+            // the task is put to top-left quadrant, the actual visible area would not start at
+            // (0,0) after it's adjusted for the status bar.
+            task.getDimBounds(mTmpRect);
+            mTmpRect.inset(-delta, -delta);
+            if (mTmpRect.contains(x, y)) {
+                mTmpRect.inset(delta, delta);
+
+                results.searchDone = true;
+
+                if (!mTmpRect.contains(x, y)) {
+                    results.taskForResize = task;
+                    return;
+                }
+                // User touched inside the task. No need to look further,
+                // focus transfer will be handled in ACTION_UP.
+                return;
+            }
+        }
+    }
+
+    void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
+            Rect contentRect, Rect postExclude) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            final Task task = mChildren.get(i);
+            ActivityRecord topVisibleActivity = task.getTopVisibleActivity();
+            if (topVisibleActivity == null || !topVisibleActivity.hasContentToDisplay()) {
+                continue;
+            }
+
+            /**
+             * Exclusion region is the region that TapDetector doesn't care about.
+             * Here we want to remove all non-focused tasks from the exclusion region.
+             * We also remove the outside touch area for resizing for all freeform
+             * tasks (including the focused).
+             *
+             * We save the focused task region once we find it, and add it back at the end.
+             *
+             * If the task is home stack and it is resizable in the minimized state, we want to
+             * exclude the docked stack from touch so we need the entire screen area and not just a
+             * small portion which the home stack currently is resized to.
+             */
+
+            if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
+                mDisplayContent.getBounds(mTmpRect);
+            } else {
+                task.getDimBounds(mTmpRect);
+            }
+
+            if (task == focusedTask) {
+                // Add the focused task rect back into the exclude region once we are done
+                // processing stacks.
+                postExclude.set(mTmpRect);
+            }
+
+            final boolean isFreeformed = task.inFreeformWindowingMode();
+            if (task != focusedTask || isFreeformed) {
+                if (isFreeformed) {
+                    // If the task is freeformed, enlarge the area to account for outside
+                    // touch area for resize.
+                    mTmpRect.inset(-delta, -delta);
+                    // Intersect with display content rect. If we have system decor (status bar/
+                    // navigation bar), we want to exclude that from the tap detection.
+                    // Otherwise, if the app is partially placed under some system button (eg.
+                    // Recents, Home), pressing that button would cause a full series of
+                    // unwanted transfer focus/resume/pause, before we could go home.
+                    mTmpRect.intersect(contentRect);
+                }
+                touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
+            }
+        }
+    }
+
+    public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
+        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
+        synchronized (mWmService.mGlobalLock) {
+            if (mCancelCurrentBoundsAnimation) {
+                return false;
+            }
+        }
+
+        try {
+            mWmService.mActivityTaskManager.resizePinnedStack(stackBounds, tempTaskBounds);
+        } catch (RemoteException e) {
+            // I don't believe you.
+        }
+        return true;
+    }
+
+    void onAllWindowsDrawn() {
+        if (!mBoundsAnimating && !mBoundsAnimatingRequested) {
+            return;
+        }
+
+        getDisplayContent().mBoundsAnimationController.onAllWindowsDrawn();
+    }
+
+    @Override  // AnimatesBounds
+    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
+            @BoundsAnimationController.AnimationType int animationType) {
+        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
+        synchronized (mWmService.mGlobalLock) {
+            if (!isAttached()) {
+                // Don't run the animation if the stack is already detached
+                return false;
+            }
+
+            if (animationType == BoundsAnimationController.BOUNDS) {
+                mBoundsAnimatingRequested = false;
+                mBoundsAnimating = true;
+            }
+            mAnimationType = animationType;
+
+            // If we are changing UI mode, as in the PiP to fullscreen
+            // transition, then we need to wait for the window to draw.
+            if (schedulePipModeChangedCallback) {
+                forAllWindows((w) -> {
+                    w.mWinAnimator.resetDrawState();
+                }, false /* traverseTopToBottom */);
+            }
+        }
+
+        if (inPinnedWindowingMode()) {
+            try {
+                mWmService.mActivityTaskManager.notifyPinnedStackAnimationStarted();
+            } catch (RemoteException e) {
+                // I don't believe you...
+            }
+
+            if ((schedulePipModeChangedCallback || animationType == FADE_IN)) {
+                // We need to schedule the PiP mode change before the animation up. It is possible
+                // in this case for the animation down to not have been completed, so always
+                // force-schedule and update to the client to ensure that it is notified that it
+                // is no longer in picture-in-picture mode
+                updatePictureInPictureModeForPinnedStackAnimation(null, forceUpdate);
+            }
+        }
+        return true;
+    }
+
+    @Override  // AnimatesBounds
+    public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
+            boolean moveToFullscreen) {
+        synchronized (mWmService.mGlobalLock) {
+            if (inPinnedWindowingMode()) {
+                // Update to the final bounds if requested. This is done here instead of in the
+                // bounds animator to allow us to coordinate this after we notify the PiP mode
+                // changed
+
+                if (schedulePipModeChangedCallback) {
+                    // We need to schedule the PiP mode change after the animation down, so use the
+                    // final bounds
+                    updatePictureInPictureModeForPinnedStackAnimation(mBoundsAnimationTarget,
+                            false /* forceUpdate */);
+                }
+
+                if (mAnimationType == BoundsAnimationController.FADE_IN) {
+                    setPinnedStackAlpha(1f);
+                    mWmService.mAtmService.notifyPinnedStackAnimationEnded();
+                    return;
+                }
+
+                if (finalStackSize != null && !mCancelCurrentBoundsAnimation) {
+                    setPinnedStackSize(finalStackSize, null);
+                } else {
+                    // We have been canceled, so the final stack size is null, still run the
+                    // animation-end logic
+                    onPipAnimationEndResize();
+                }
+
+                mWmService.mAtmService.notifyPinnedStackAnimationEnded();
+                if (moveToFullscreen) {
+                    ((ActivityStack) this).dismissPip();
+                }
+            } else {
+                // No PiP animation, just run the normal animation-end logic
+                onPipAnimationEndResize();
+            }
+        }
+    }
+
+    /**
+     * Sets the current picture-in-picture aspect ratio.
+     */
+    void setPictureInPictureAspectRatio(float aspectRatio) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        final DisplayContent displayContent = getDisplayContent();
+        if (displayContent == null) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        final PinnedStackController pinnedStackController =
+                getDisplayContent().getPinnedStackController();
+
+        if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
+            return;
+        }
+
+        // Notify the pinned stack controller about aspect ratio change.
+        // This would result a callback delivered from SystemUI to WM to start animation,
+        // if the bounds are ought to be altered due to aspect ratio change.
+        pinnedStackController.setAspectRatio(
+                pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
+                        ? aspectRatio : -1f);
+    }
+
+    /**
+     * Sets the current picture-in-picture actions.
+     */
+    void setPictureInPictureActions(List<RemoteAction> actions) {
+        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
+            return;
+        }
+
+        if (!inPinnedWindowingMode()) {
+            return;
+        }
+
+        getDisplayContent().getPinnedStackController().setActions(actions);
+    }
+
+    /** Called immediately prior to resizing the tasks at the end of the pinned stack animation. */
+    void onPipAnimationEndResize() {
+        mBoundsAnimating = false;
+        for (int i = 0; i < mChildren.size(); i++) {
+            final Task t = mChildren.get(i);
+            t.clearPreserveNonFloatingState();
+        }
+        mWmService.requestTraversal();
+    }
+
+    @Override
+    public boolean shouldDeferStartOnMoveToFullscreen() {
+        synchronized (mWmService.mGlobalLock) {
+            if (!isAttached()) {
+                // Unnecessary to pause the animation because the stack is detached.
+                return false;
+            }
+
+            // Workaround for the recents animation -- normally we need to wait for the new activity
+            // to show before starting the PiP animation, but because we start and show the home
+            // activity early for the recents animation prior to the PiP animation starting, there
+            // is no subsequent all-drawn signal. In this case, we can skip the pause when the home
+            // stack is already visible and drawn.
+            final ActivityStack homeStack = mDisplayContent.getHomeStack();
+            if (homeStack == null) {
+                return true;
+            }
+            final Task homeTask = homeStack.getTopChild();
+            if (homeTask == null) {
+                return true;
+            }
+            final ActivityRecord homeApp = homeTask.getTopVisibleActivity();
+            if (!homeTask.isVisible() || homeApp == null) {
+                return true;
+            }
+            return !homeApp.allDrawn;
+        }
+    }
+
+    /**
+     * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
+     *         bounds and we have a deferred PiP mode changed callback set with the animation.
+     */
+    public boolean deferScheduleMultiWindowModeChanged() {
+        if (inPinnedWindowingMode()) {
+            // For the pinned stack, the deferring of the multi-window mode changed is tied to the
+            // transition animation into picture-in-picture, and is called once the animation
+            // completes, or is interrupted in a way that would leave the stack in a non-fullscreen
+            // state.
+            // @see BoundsAnimationController
+            // @see BoundsAnimationControllerTests
+            return (mBoundsAnimatingRequested || mBoundsAnimating);
+        }
+        return false;
+    }
+
+    public boolean isForceScaled() {
+        return mBoundsAnimating;
+    }
+
+    public boolean isAnimatingBounds() {
+        return mBoundsAnimating;
+    }
+
+    public boolean lastAnimatingBoundsWasToFullscreen() {
+        return mBoundsAnimatingToFullscreen;
+    }
+
+    public boolean isAnimatingBoundsToFullscreen() {
+        return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen();
+    }
+
+    public boolean pinnedStackResizeDisallowed() {
+        if (mBoundsAnimating && mCancelCurrentBoundsAnimation) {
+            return true;
+        }
+        return false;
+    }
+
+    /** Returns true if a removal action is still being deferred. */
+    boolean checkCompleteDeferredRemoval() {
+        if (isAnimating(TRANSITION | CHILDREN)) {
+            return true;
+        }
+        if (mDeferRemoval) {
+            removeImmediately();
+        }
+
+        return super.checkCompleteDeferredRemoval();
+    }
+
+    @Override
+    int getOrientation() {
+        return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
+    }
+
+    private boolean canSpecifyOrientation() {
+        final int windowingMode = getWindowingMode();
+        final int activityType = getActivityType();
+        return windowingMode == WINDOWING_MODE_FULLSCREEN
+                || activityType == ACTIVITY_TYPE_HOME
+                || activityType == ACTIVITY_TYPE_RECENTS
+                || activityType == ACTIVITY_TYPE_ASSISTANT;
+    }
+
+    @Override
+    Dimmer getDimmer() {
+        return mDimmer;
+    }
+
+    @Override
+    void prepareSurfaces() {
+        mDimmer.resetDimStates();
+        super.prepareSurfaces();
+        getDimBounds(mTmpDimBoundsRect);
+
+        // Bounds need to be relative, as the dim layer is a child.
+        mTmpDimBoundsRect.offsetTo(0, 0);
+        if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+            scheduleAnimation();
+        }
+    }
+
+    @Override
+    public boolean setPinnedStackAlpha(float alpha) {
+        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
+        synchronized (mWmService.mGlobalLock) {
+            final SurfaceControl sc = getSurfaceControl();
+            if (sc == null || !sc.isValid()) {
+                // If the stack is already removed, don't bother updating any stack animation
+                return false;
+            }
+            getPendingTransaction().setAlpha(sc, mCancelCurrentBoundsAnimation ? 1 : alpha);
+            scheduleAnimation();
+            return !mCancelCurrentBoundsAnimation;
+        }
+    }
+
+    public DisplayInfo getDisplayInfo() {
+        return mDisplayContent.getDisplayInfo();
+    }
+
+    void dim(float alpha) {
+        mDimmer.dimAbove(getPendingTransaction(), alpha);
+        scheduleAnimation();
+    }
+
+    void stopDimming() {
+        mDimmer.stopDim(getPendingTransaction());
+        scheduleAnimation();
+    }
+
+    AnimatingActivityRegistry getAnimatingActivityRegistry() {
+        return mAnimatingActivityRegistry;
+    }
+
+    @Override
+    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
+            Rect outSurfaceInsets) {
+        final Task task = getTopChild();
+        if (task != null) {
+            task.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        } else {
+            super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
+        }
+    }
+
+    @Override
+    RemoteAnimationTarget createRemoteAnimationTarget(
+            RemoteAnimationController.RemoteAnimationRecord record) {
+        final Task task = getTopChild();
+        return task != null ? task.createRemoteAnimationTarget(record) : null;
+    }
+
     @Override
     public String toString() {
         return "ActivityStack{" + Integer.toHexString(System.identityHashCode(this))
@@ -5036,11 +6486,11 @@
     public void writeToProto(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
         final long token = proto.start(fieldId);
-        super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
-        proto.write(ID, mStackId);
+        writeToProtoInnerStackOnly(proto, STACK, logLevel);
+        proto.write(com.android.server.am.ActivityStackProto.ID, mStackId);
         for (int taskNdx = getChildCount() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = getChildAt(taskNdx);
-            task.writeToProto(proto, TASKS, logLevel);
+            final Task task = getChildAt(taskNdx);
+            task.writeToProto(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
         }
         if (mResumedActivity != null) {
             mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
@@ -5048,11 +6498,36 @@
         proto.write(DISPLAY_ID, mDisplayId);
         if (!matchParentBounds()) {
             final Rect bounds = getRequestedOverrideBounds();
-            bounds.writeToProto(proto, BOUNDS);
+            bounds.writeToProto(proto, com.android.server.am.ActivityStackProto.BOUNDS);
         }
 
         // TODO: Remove, no longer needed with windowingMode.
         proto.write(FULLSCREEN, matchParentBounds());
         proto.end(token);
     }
+
+    // TODO(proto-merge): Remove once protos for ActivityStack and TaskStack are merged.
+    void writeToProtoInnerStackOnly(ProtoOutputStream proto, long fieldId,
+            @WindowTraceLogLevel int logLevel) {
+        if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
+            return;
+        }
+
+        final long token = proto.start(fieldId);
+        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
+        proto.write(StackProto.ID, mStackId);
+        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
+            mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, StackProto.TASKS, logLevel);
+        }
+        proto.write(FILLS_PARENT, matchParentBounds());
+        getRawBounds().writeToProto(proto, StackProto.BOUNDS);
+        proto.write(DEFER_REMOVAL, mDeferRemoval);
+        proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
+        proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
+        proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
+        proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
+        mAdjustedBounds.writeToProto(proto, ADJUSTED_BOUNDS);
+        proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
+        proto.end(token);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 5f1c001..016654f 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -75,12 +75,12 @@
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
 import static com.android.server.wm.RootActivityContainer.TAG_STATES;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -740,7 +740,7 @@
             return false;
         }
 
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         final ActivityStack stack = task.getStack();
 
         beginDeferResume();
@@ -913,7 +913,7 @@
         }
 
         r.launchFailed = false;
-        if (stack.updateLRUListLocked(r)) {
+        if (stack.updateLruList(r)) {
             Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
         }
 
@@ -1382,7 +1382,7 @@
     }
 
     /** This doesn't just find a task, it also moves the task to front. */
-    void findTaskToMoveToFront(TaskRecord task, int flags, ActivityOptions options, String reason,
+    void findTaskToMoveToFront(Task task, int flags, ActivityOptions options, String reason,
             boolean forceNonResizeable) {
         ActivityStack currentStack = task.getStack();
         if (currentStack == null) {
@@ -1480,7 +1480,7 @@
         continueUpdateRecentsHomeStackBounds();
         for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) {
             final int taskId = mResizingTasksDuringAnimation.valueAt(i);
-            final TaskRecord task =
+            final Task task =
                     mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_ONLY);
             if (task != null) {
                 task.setTaskDockedResizing(false);
@@ -1527,13 +1527,13 @@
             // the picture-in-picture mode.
             final boolean schedulePictureInPictureModeChange =
                     windowingMode == WINDOWING_MODE_PINNED;
-            final ArrayList<TaskRecord> tasks = fromStack.getAllTasks();
+            final ArrayList<Task> tasks = fromStack.getAllTasks();
 
             if (!tasks.isEmpty()) {
                 mTmpOptions.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
                 final int size = tasks.size();
                 for (int i = 0; i < size; ++i) {
-                    final TaskRecord task = tasks.get(i);
+                    final Task task = tasks.get(i);
                     final ActivityStack toStack = toDisplay.getOrCreateStack(
                                 null, mTmpOptions, task, task.getActivityType(), onTop);
 
@@ -1709,15 +1709,6 @@
             return;
         }
 
-        // It is possible for the bounds animation from the WM to call this but be delayed by
-        // another AM call that is holding the AMS lock. In such a case, the pinnedBounds may be
-        // incorrect if AMS.resizeStackWithBoundsFromWindowManager() is already called while waiting
-        // for the AMS lock to be freed. So check and make sure these bounds are still good.
-        final TaskStack stackController = stack.getTaskStack();
-        if (stackController.pinnedStackResizeDisallowed()) {
-            return;
-        }
-
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizePinnedStack");
         mService.deferWindowLayout();
         try {
@@ -1745,7 +1736,7 @@
     }
 
     private void removeStackInSurfaceTransaction(ActivityStack stack) {
-        final ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        final ArrayList<Task> tasks = stack.getAllTasks();
         if (stack.getWindowingMode() == WINDOWING_MODE_PINNED) {
             /**
              * Workaround: Force-stop all the activities in the pinned stack before we reparent them
@@ -1791,14 +1782,14 @@
      */
     boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
             String reason) {
-        final TaskRecord tr =
+        final Task task =
                 mRootActivityContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
-        if (tr != null) {
-            tr.removeTaskActivitiesLocked(reason);
-            cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
-            mService.getLockTaskController().clearLockedTask(tr);
+        if (task != null) {
+            task.removeTaskActivitiesLocked(reason);
+            cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);
+            mService.getLockTaskController().clearLockedTask(task);
             mService.getTaskChangeNotificationController().notifyTaskStackChanged();
-            if (tr.isPersistable) {
+            if (task.isPersistable) {
                 mService.notifyTaskPersisterLocked(null, true);
             }
             return true;
@@ -1807,19 +1798,19 @@
         return false;
     }
 
-    void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) {
+    void cleanUpRemovedTaskLocked(Task task, boolean killProcess, boolean removeFromRecents) {
         if (removeFromRecents) {
-            mRecentTasks.remove(tr);
+            mRecentTasks.remove(task);
         }
-        ComponentName component = tr.getBaseIntent().getComponent();
+        ComponentName component = task.getBaseIntent().getComponent();
         if (component == null) {
-            Slog.w(TAG, "No component for base intent of task: " + tr);
+            Slog.w(TAG, "No component for base intent of task: " + task);
             return;
         }
 
         // Find any running services associated with this app and stop if needed.
         final Message msg = PooledLambda.obtainMessage(ActivityManagerInternal::cleanUpServices,
-                mService.mAmInternal, tr.mUserId, component, new Intent(tr.getBaseIntent()));
+                mService.mAmInternal, task.mUserId, component, new Intent(task.getBaseIntent()));
         mService.mH.sendMessage(msg);
 
         if (!killProcess) {
@@ -1836,7 +1827,7 @@
             SparseArray<WindowProcessController> uids = pmap.valueAt(i);
             for (int j = 0; j < uids.size(); j++) {
                 WindowProcessController proc = uids.valueAt(j);
-                if (proc.mUserId != tr.mUserId) {
+                if (proc.mUserId != task.mUserId) {
                     // Don't kill process for a different user.
                     continue;
                 }
@@ -1849,7 +1840,7 @@
                     continue;
                 }
 
-                if (!proc.shouldKillProcessForRemovedTask(tr)) {
+                if (!proc.shouldKillProcessForRemovedTask(task)) {
                     // Don't kill process(es) that has an activity in a different task that is also
                     // in recents, or has an activity not stopped.
                     return;
@@ -1881,7 +1872,7 @@
      * @param onTop If the stack for the task should be the topmost on the display.
      * @return true if the task has been restored successfully.
      */
-    boolean restoreRecentTaskLocked(TaskRecord task, ActivityOptions aOptions, boolean onTop) {
+    boolean restoreRecentTaskLocked(Task task, ActivityOptions aOptions, boolean onTop) {
         final ActivityStack stack =
                 mRootActivityContainer.getLaunchStack(null, aOptions, task, onTop);
         final ActivityStack currentStack = task.getStack();
@@ -1893,8 +1884,7 @@
 
         if (currentStack != null) {
             // Task has already been restored once. Just re-parent it to the new stack.
-            task.reparent(stack.mTaskStack,
-                    POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked");
+            task.reparent(stack, POSITION_TOP, true /*moveParents*/, "restoreRecentTaskLocked");
             return true;
         }
 
@@ -1905,12 +1895,12 @@
     }
 
     @Override
-    public void onRecentTaskAdded(TaskRecord task) {
+    public void onRecentTaskAdded(Task task) {
         task.touchActiveTime();
     }
 
     @Override
-    public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+    public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
         if (wasTrimmed) {
             // Task was trimmed from the recent tasks list -- remove the active task record as well
             // since the user won't really be able to go back to it
@@ -1925,7 +1915,7 @@
      * the various checks on tasks that are going to be reparented from one stack to another.
      */
     // TODO: Look into changing users to this method to ActivityDisplay.resolveWindowingMode()
-    ActivityStack getReparentTargetStack(TaskRecord task, ActivityStack stack, boolean toTop) {
+    ActivityStack getReparentTargetStack(Task task, ActivityStack stack, boolean toTop) {
         final ActivityStack prevStack = task.getStack();
         final int stackId = stack.mStackId;
         final boolean inMultiWindowMode = stack.inMultiWindowMode();
@@ -2078,7 +2068,7 @@
 
     // Called when WindowManager has finished animating the launchingBehind activity to the back.
     private void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         final ActivityStack stack = task.getStack();
 
         mRecentTasks.add(task);
@@ -2089,7 +2079,7 @@
         // task has been shown briefly
         final ActivityRecord top = stack.getTopActivity();
         if (top != null) {
-            top.getTaskRecord().touchActiveTime();
+            top.getTask().touchActiveTime();
         }
     }
 
@@ -2208,7 +2198,7 @@
 
     static boolean dumpHistoryList(FileDescriptor fd, PrintWriter pw, List<ActivityRecord> list,
             String prefix, String label, boolean complete, boolean brief, boolean client,
-            String dumpPackage, boolean needNL, String header, TaskRecord lastTask) {
+            String dumpPackage, boolean needNL, String header, Task lastTask) {
         String innerPrefix = null;
         String[] args = null;
         boolean printed = false;
@@ -2231,8 +2221,8 @@
                 pw.println(header);
                 header = null;
             }
-            if (lastTask != r.getTaskRecord()) {
-                lastTask = r.getTaskRecord();
+            if (lastTask != r.getTask()) {
+                lastTask = r.getTask();
                 pw.print(prefix);
                 pw.print(full ? "* " : "  ");
                 pw.println(lastTask);
@@ -2392,13 +2382,13 @@
                 WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION);
     }
 
-    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
+    void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode,
             int preferredDisplayId, ActivityStack actualStack) {
         handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId,
                 actualStack, false /* forceNonResizable */);
     }
 
-    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredWindowingMode,
+    void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode,
             int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) {
         final boolean isSecondaryDisplayPreferred =
                 (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY);
@@ -2467,10 +2457,10 @@
     }
 
     /** Notifies that the top activity of the task is forced to be resizeable. */
-    private void handleForcedResizableTaskIfNeeded(TaskRecord task, int reason) {
+    private void handleForcedResizableTaskIfNeeded(Task task, int reason) {
         final ActivityRecord topActivity = task.getTopActivity();
         if (topActivity == null || topActivity.noDisplay
-                || !topActivity.isNonResizableOrForcedResizable()) {
+                || !topActivity.isNonResizableOrForcedResizable(task.getWindowingMode())) {
             return;
         }
         mService.getTaskChangeNotificationController().notifyActivityForcedResizable(
@@ -2491,7 +2481,7 @@
         mActivityMetricsLogger.logWindowState();
     }
 
-    void scheduleUpdateMultiWindowMode(TaskRecord task) {
+    void scheduleUpdateMultiWindowMode(Task task) {
         // If the stack is animating in a way where we will be forcing a multi-mode change at the
         // end, then ensure that we defer all in between multi-window mode changes
         if (task.getStack().deferScheduleMultiWindowModeChanged()) {
@@ -2510,7 +2500,7 @@
         }
     }
 
-    void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, ActivityStack prevStack) {
+    void scheduleUpdatePictureInPictureModeIfNeeded(Task task, ActivityStack prevStack) {
         final ActivityStack stack = task.getStack();
         if (prevStack == null || prevStack == stack
                 || (!prevStack.inPinnedWindowingMode() && !stack.inPinnedWindowingMode())) {
@@ -2520,7 +2510,7 @@
         scheduleUpdatePictureInPictureModeIfNeeded(task, stack.getRequestedOverrideBounds());
     }
 
-    void scheduleUpdatePictureInPictureModeIfNeeded(TaskRecord task, Rect targetStackBounds) {
+    void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetStackBounds) {
         for (int i = task.getChildCount() - 1; i >= 0; i--) {
             final ActivityRecord r = task.getChildAt(i);
             if (r.attachedToProcess()) {
@@ -2538,7 +2528,7 @@
         }
     }
 
-    void updatePictureInPictureMode(TaskRecord task, Rect targetStackBounds, boolean forceUpdate) {
+    void updatePictureInPictureMode(Task task, Rect targetStackBounds, boolean forceUpdate) {
         mHandler.removeMessages(REPORT_PIP_MODE_CHANGED_MSG);
         for (int i = task.getChildCount() - 1; i >= 0; i--) {
             final ActivityRecord r = task.getChildAt(i);
@@ -2695,14 +2685,14 @@
      *
      * @param task The task to put into resizing mode
      */
-    void setResizingDuringAnimation(TaskRecord task) {
+    void setResizingDuringAnimation(Task task) {
         mResizingTasksDuringAnimation.add(task.mTaskId);
         task.setTaskDockedResizing(true);
     }
 
     int startActivityFromRecents(int callingPid, int callingUid, int taskId,
             SafeActivityOptions options) {
-        TaskRecord task = null;
+        Task task = null;
         final String callingPackage;
         final Intent intent;
         final int userId;
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index e2e2b74..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)
@@ -271,7 +279,7 @@
     final int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
             String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
-            int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+            int userId, Task inTask, String reason, boolean validateIncomingUser,
             PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart) {
 
         userId = checkTargetUser(userId, validateIncomingUser, realCallingPid, realCallingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index effd154a..8420695 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -97,7 +97,7 @@
     ResolveInfo mRInfo;
     ActivityInfo mAInfo;
     String mResolvedType;
-    TaskRecord mInTask;
+    Task mInTask;
     ActivityOptions mActivityOptions;
 
     ActivityStartInterceptor(
@@ -144,7 +144,7 @@
      * @return true if an interception occurred
      */
     boolean intercept(Intent intent, ResolveInfo rInfo, ActivityInfo aInfo, String resolvedType,
-            TaskRecord inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
+            Task inTask, int callingPid, int callingUid, ActivityOptions activityOptions) {
         mUserManager = UserManager.get(mServiceContext);
 
         mIntent = intent;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 77165f2..2218c72 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -82,7 +82,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS;
 import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_DISPLAY;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -175,9 +175,9 @@
     // The display to launch the activity onto, barring any strong reason to do otherwise.
     private int mPreferredDisplayId;
 
-    private TaskRecord mInTask;
+    private Task mInTask;
     private boolean mAddingToTask;
-    private TaskRecord mReuseTask;
+    private Task mReuseTask;
 
     private ActivityInfo mNewTaskInfo;
     private Intent mNewTaskIntent;
@@ -330,7 +330,7 @@
         boolean componentSpecified;
         boolean avoidMoveToFront;
         ActivityRecord[] outActivity;
-        TaskRecord inTask;
+        Task inTask;
         String reason;
         ProfilerInfo profilerInfo;
         Configuration globalConfig;
@@ -571,7 +571,7 @@
      */
     void startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+            int startFlags, boolean doResume, ActivityOptions options, Task inTask) {
         try {
             mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
             mLastStartReason = "startResolvedActivity";
@@ -808,7 +808,7 @@
         final int realCallingUid = request.realCallingUid;
         final int startFlags = request.startFlags;
         final SafeActivityOptions options = request.activityOptions;
-        TaskRecord inTask = request.inTask;
+        Task inTask = request.inTask;
 
         int err = ActivityManager.START_SUCCESS;
         // Pull the optional Ephemeral Installer-only bundle out of the options early.
@@ -895,7 +895,7 @@
         }
 
         if (err == ActivityManager.START_SUCCESS && sourceRecord != null
-                && sourceRecord.getTaskRecord().voiceSession != null) {
+                && sourceRecord.getTask().voiceSession != null) {
             // If this activity is being launched as part of a voice session, we need to ensure
             // that it is safe to do so.  If the upcoming activity will also be part of the voice
             // session, we can only launch it if it has explicitly said it supports the VOICE
@@ -1392,7 +1392,7 @@
      */
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
                 IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-                int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+                int startFlags, boolean doResume, ActivityOptions options, Task inTask,
                 boolean restrictedBgActivity) {
         int result = START_CANCELED;
         final ActivityStack startedActivityStack;
@@ -1449,7 +1449,7 @@
         if (startedActivityStack != null && startedActivityStack.isAttached()
                 && startedActivityStack.numActivities() == 0
                 && !startedActivityStack.isActivityTypeHome()) {
-            startedActivityStack.remove();
+            startedActivityStack.removeIfPossible();
             startedActivityStack = null;
         }
         return startedActivityStack;
@@ -1464,7 +1464,7 @@
      */
     private int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
-            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+            int startFlags, boolean doResume, ActivityOptions options, Task inTask,
             boolean restrictedBgActivity) {
         setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
                 voiceInteractor, restrictedBgActivity);
@@ -1477,7 +1477,7 @@
 
         mIntent.setFlags(mLaunchFlags);
 
-        final TaskRecord reusedTask = getReusableTask();
+        final Task reusedTask = getReusableTask();
         mSupervisor.getLaunchParamsController().calculate(reusedTask != null ? reusedTask : mInTask,
                 r.info.windowLayout, r, sourceRecord, options, PHASE_BOUNDS, mLaunchParams);
         mPreferredDisplayId =
@@ -1493,7 +1493,7 @@
         }
 
         // Compute if there is an existing task that should be used for.
-        final TaskRecord targetTask = reusedTask != null ? reusedTask : computeTargetTask();
+        final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
         final boolean newTask = targetTask == null;
 
         // Check if starting activity on given task or on a new task is allowed.
@@ -1525,11 +1525,11 @@
             mTargetStack = computeStackFocus(mStartActivity, true, mLaunchFlags, mOptions);
         }
         if (newTask) {
-            final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
-                    ? mSourceRecord.getTaskRecord() : null;
+            final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+                    ? mSourceRecord.getTask() : null;
             setNewTask(taskToAffiliate);
             if (mService.getLockTaskController().isLockTaskModeViolation(
-                    mStartActivity.getTaskRecord())) {
+                    mStartActivity.getTask())) {
                 Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
                 return START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
@@ -1550,10 +1550,10 @@
         );
         if (newTask) {
             EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, mStartActivity.mUserId,
-                    mStartActivity.getTaskRecord().mTaskId);
+                    mStartActivity.getTask().mTaskId);
         }
         mStartActivity.logStartActivity(
-                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTaskRecord());
+                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity.getTask());
         mTargetStack.mLastPausedActivity = null;
 
         mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
@@ -1563,7 +1563,7 @@
                 mKeepCurTransition, mOptions);
         if (mDoResume) {
             final ActivityRecord topTaskActivity =
-                    mStartActivity.getTaskRecord().topRunningActivityLocked();
+                    mStartActivity.getTask().topRunningActivityLocked();
             if (!mTargetStack.isFocusable()
                     || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                     && mStartActivity != topTaskActivity)) {
@@ -1591,36 +1591,36 @@
                         mTargetStack, mStartActivity, mOptions);
             }
         } else if (mStartActivity != null) {
-            mSupervisor.mRecentTasks.add(mStartActivity.getTaskRecord());
+            mSupervisor.mRecentTasks.add(mStartActivity.getTask());
         }
         mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
 
-        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTaskRecord(),
+        mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
                 preferredWindowingMode, mPreferredDisplayId, mTargetStack);
 
         return START_SUCCESS;
     }
 
-    private TaskRecord computeTargetTask() {
+    private Task computeTargetTask() {
         if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                 && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             // A new task should be created instead of using existing one.
             return null;
         } else if (mSourceRecord != null) {
-            return mSourceRecord.getTaskRecord();
+            return mSourceRecord.getTask();
         } else if (mInTask != null) {
             return mInTask;
         } else {
             final ActivityRecord top = computeStackFocus(mStartActivity, false /* newTask */,
                     mLaunchFlags, mOptions).getTopActivity();
             if (top != null) {
-                return top.getTaskRecord();
+                return top.getTask();
             }
         }
         return null;
     }
 
-    private int isAllowedToStart(ActivityRecord r, boolean newTask, TaskRecord targetTask) {
+    private int isAllowedToStart(ActivityRecord r, boolean newTask, Task targetTask) {
         if (mStartActivity.packageName == null) {
             if (mStartActivity.resultTo != null) {
                 mStartActivity.resultTo.sendResult(INVALID_UID, mStartActivity.resultWho,
@@ -1666,8 +1666,7 @@
      * - Comply to the specified activity launch flags
      * - Determine whether need to add a new activity on top or just brought the task to front.
      */
-    private int recycleTask(TaskRecord targetTask, ActivityRecord targetTaskTop,
-            TaskRecord reusedTask) {
+    private int recycleTask(Task targetTask, ActivityRecord targetTaskTop, Task reusedTask) {
         // True if we are clearing top and resetting of a standard (default) launch mode
         // ({@code LAUNCH_MULTIPLE}) activity. The existing activity will be finished.
         final boolean clearTopAndResetStandardLaunchMode =
@@ -1680,7 +1679,7 @@
             // If mStartActivity does not have a task associated with it, associate it with the
             // reused activity's task. Do not do so if we're clearing top and resetting for a
             // standard launchMode activity.
-            if (mStartActivity.getTaskRecord() == null && !clearTopAndResetStandardLaunchMode) {
+            if (mStartActivity.getTask() == null && !clearTopAndResetStandardLaunchMode) {
                 mStartActivity.setTaskForReuse(reusedTask);
                 clearTaskForReuse = true;
             }
@@ -1796,7 +1795,7 @@
 
         // Don't use mStartActivity.task to show the toast. We're not starting a new activity but
         // reusing 'top'. Fields in mStartActivity may not be fully initialized.
-        mSupervisor.handleNonResizableTaskIfNeeded(top.getTaskRecord(),
+        mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(),
                 mLaunchParams.mWindowingMode, mPreferredDisplayId, topStack);
 
         return START_DELIVERED_TO_TOP;
@@ -1806,7 +1805,7 @@
      * Applying the launching flags to the task, which might clear few or all the activities in the
      * task.
      */
-    private void complyActivityFlags(TaskRecord targetTask, ActivityRecord reusedActivity) {
+    private void complyActivityFlags(Task targetTask, ActivityRecord reusedActivity) {
         ActivityRecord targetTaskTop = targetTask.getTopActivity();
         final boolean resetTask =
                 reusedActivity != null && (mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0;
@@ -1818,10 +1817,10 @@
                 == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
             // The caller has requested to completely replace any existing task with its new
             // activity. Well that should not be too hard...
-            // Note: we must persist the {@link TaskRecord} first as intentActivity could be
+            // Note: we must persist the {@link Task} first as intentActivity could be
             // removed from calling performClearTaskLocked (For example, if it is being brought out
             // of history or if it is finished immediately), thus disassociating the task. Also note
-            // that mReuseTask is reset as a result of {@link TaskRecord#performClearTaskLocked}
+            // that mReuseTask is reset as a result of {@link Task#performClearTaskLocked}
             // launching another activity.
             // TODO(b/36119896):  We shouldn't trigger activity launches in this path since we are
             // already launching one.
@@ -1838,9 +1837,9 @@
                     mLaunchFlags);
 
             // The above code can remove {@code reusedActivity} from the task, leading to the
-            // {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The task
+            // {@code ActivityRecord} removing its reference to the {@code Task}. The task
             // reference is needed in the call below to {@link setTargetStackAndMoveToFrontIfNeeded}
-            if (targetTaskTop.getTaskRecord() == null) {
+            if (targetTaskTop.getTask() == null) {
                 targetTask.addChild(targetTaskTop);
             }
 
@@ -1848,7 +1847,7 @@
                 if (top.isRootOfTask()) {
                     // Activity aliases may mean we use different intents for the top activity,
                     // so make sure the task now has the identity of the new intent.
-                    top.getTaskRecord().setIntent(mStartActivity);
+                    top.getTask().setIntent(mStartActivity);
                 }
                 deliverNewIntent(top);
             } else {
@@ -1873,7 +1872,7 @@
             final ActivityRecord act = targetTask.findActivityInHistoryLocked(
                     mStartActivity);
             if (act != null) {
-                final TaskRecord task = act.getTaskRecord();
+                final Task task = act.getTask();
                 task.moveActivityToFrontLocked(act);
                 act.updateOptionsLocked(mOptions);
                 deliverNewIntent(act);
@@ -1894,7 +1893,7 @@
                 // activity in the task is the root activity, deliver this new intent to it if it
                 // desires.
                 if (targetTaskTop.isRootOfTask()) {
-                    targetTaskTop.getTaskRecord().setIntent(mStartActivity);
+                    targetTaskTop.getTask().setIntent(mStartActivity);
                 }
                 deliverNewIntent(targetTaskTop);
             } else if (!targetTask.isSameIntentFilter(mStartActivity)) {
@@ -1968,7 +1967,7 @@
         }
     }
 
-    private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+    private void setInitialState(ActivityRecord r, ActivityOptions options, Task inTask,
             boolean doResume, int startFlags, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             boolean restrictedBgActivity) {
@@ -2036,7 +2035,7 @@
             if (mOptions.getLaunchTaskId() != -1 && mOptions.getTaskOverlay()) {
                 r.mTaskOverlay = true;
                 if (!mOptions.canTaskOverlayResume()) {
-                    final TaskRecord task = mRootActivityContainer.anyTaskForId(
+                    final Task task = mRootActivityContainer.anyTaskForId(
                             mOptions.getLaunchTaskId());
                     final ActivityRecord top = task != null ? task.getTopActivity() : null;
                     if (top != null && !top.isState(RESUMED)) {
@@ -2210,7 +2209,7 @@
             // example, if this method is being called for processing a pending activity launch, it
             // is possible that the activity has been removed from the task after the launch was
             // enqueued.
-            final TaskRecord sourceTask = mSourceRecord.getTaskRecord();
+            final Task sourceTask = mSourceRecord.getTask();
             mNewTaskIntent = sourceTask != null ? sourceTask.intent : null;
         }
         mSourceRecord = null;
@@ -2221,7 +2220,7 @@
      * Decide whether the new activity should be inserted into an existing task. Returns null
      * if not or an ActivityRecord with the task into which the new activity should be added.
      */
-    private TaskRecord getReusableTask() {
+    private Task getReusableTask() {
         // We may want to try to place the new activity in to an existing task.  We always
         // do this if the target activity is singleTask or singleInstance; we will also do
         // this if NEW_TASK has been requested, and there is not an additional qualifier telling
@@ -2236,7 +2235,7 @@
         putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
         ActivityRecord intentActivity = null;
         if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
-            TaskRecord launchTask = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId());
+            Task launchTask = mRootActivityContainer.anyTaskForId(mOptions.getLaunchTaskId());
             if (launchTask != null) {
                 return launchTask;
             }
@@ -2265,7 +2264,7 @@
             intentActivity = null;
         }
 
-        return intentActivity != null ? intentActivity.getTaskRecord() : null;
+        return intentActivity != null ? intentActivity.getTask() : null;
     }
 
     /**
@@ -2286,8 +2285,8 @@
             final ActivityStack focusStack = mTargetStack.getDisplay().getFocusedStack();
             final ActivityRecord curTop = (focusStack == null)
                     ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
-            final TaskRecord topTask = curTop != null ? curTop.getTaskRecord() : null;
-            differentTopTask = topTask != intentActivity.getTaskRecord()
+            final Task topTask = curTop != null ? curTop.getTask() : null;
+            differentTopTask = topTask != intentActivity.getTask()
                     || (focusStack != null && topTask != focusStack.topTask());
         } else {
             // The existing task should always be different from those in other displays.
@@ -2297,14 +2296,14 @@
         if (differentTopTask && !mAvoidMoveToFront) {
             mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
             if (mSourceRecord == null || (mSourceStack.getTopActivity() != null &&
-                    mSourceStack.getTopActivity().getTaskRecord()
-                            == mSourceRecord.getTaskRecord())) {
+                    mSourceStack.getTopActivity().getTask()
+                            == mSourceRecord.getTask())) {
                 // We really do want to push this one into the user's face, right now.
                 if (mLaunchTaskBehind && mSourceRecord != null) {
-                    intentActivity.setTaskToAffiliateWith(mSourceRecord.getTaskRecord());
+                    intentActivity.setTaskToAffiliateWith(mSourceRecord.getTask());
                 }
 
-                final TaskRecord intentTask = intentActivity.getTaskRecord();
+                final Task intentTask = intentActivity.getTask();
                 final ActivityStack launchStack =
                         getLaunchStack(mStartActivity, mLaunchFlags, intentTask, mOptions);
                 if (launchStack == null || launchStack == mTargetStack) {
@@ -2336,7 +2335,7 @@
                     // Target and computed stacks are on different displays and we've
                     // found a matching task - move the existing instance to that display and
                     // move it to front.
-                    intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
+                    intentActivity.getTask().reparent(launchStack, ON_TOP,
                             REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
                             "reparentToDisplay");
                     mMovedToFront = true;
@@ -2346,7 +2345,7 @@
                     // For example, the activity may have been initially started with an intent
                     // which placed it in the fullscreen stack. To ensure the proper handling of
                     // the activity based on home stack assumptions, we must move it over.
-                    intentActivity.getTaskRecord().reparent(launchStack, ON_TOP,
+                    intentActivity.getTask().reparent(launchStack, ON_TOP,
                             REPARENT_MOVE_STACK_TO_FRONT, ANIMATE, DEFER_RESUME,
                             "reparentingHome");
                     mMovedToFront = true;
@@ -2356,7 +2355,7 @@
                     // The task does not need to be reparented to the launch stack. Remove the
                     // launch stack if there is no activity in it.
                     Slog.w(TAG, "Removing an empty stack: " + launchStack);
-                    launchStack.remove();
+                    launchStack.removeIfPossible();
                 }
 
                 mOptions = null;
@@ -2365,7 +2364,7 @@
         // Need to update mTargetStack because if task was moved out of it, the original stack may
         // be destroyed.
         mTargetStack = intentActivity.getActivityStack();
-        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTaskRecord(),
+        mSupervisor.handleNonResizableTaskIfNeeded(intentActivity.getTask(),
                 WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, mTargetStack);
     }
 
@@ -2378,19 +2377,19 @@
         mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
     }
 
-    private void setNewTask(TaskRecord taskToAffiliate) {
+    private void setNewTask(Task taskToAffiliate) {
         final boolean toTop = !mLaunchTaskBehind && !mAvoidMoveToFront;
-        final TaskRecord task = mTargetStack.createTaskRecord(
+        final Task task = mTargetStack.createTask(
                 mSupervisor.getNextTaskIdForUserLocked(mStartActivity.mUserId),
                 mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
                 mNewTaskIntent != null ? mNewTaskIntent : mIntent, mVoiceSession,
                 mVoiceInteractor, toTop, mStartActivity, mSourceRecord, mOptions);
         addOrReparentStartingActivity(task, "setTaskFromReuseOrCreateNewTask - mReuseTask");
-        updateBounds(mStartActivity.getTaskRecord(), mLaunchParams.mBounds);
+        updateBounds(mStartActivity.getTask(), mLaunchParams.mBounds);
 
         if (DEBUG_TASKS) {
             Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
-                    + " in new task " + mStartActivity.getTaskRecord());
+                    + " in new task " + mStartActivity.getTask());
         }
 
         if (taskToAffiliate != null) {
@@ -2403,14 +2402,14 @@
             return;
         }
 
-        activity.logStartActivity(AM_NEW_INTENT, activity.getTaskRecord());
+        activity.logStartActivity(AM_NEW_INTENT, activity.getTask());
         activity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                 mStartActivity.launchedFromPackage);
         mIntentDelivered = true;
     }
 
     @VisibleForTesting
-    void updateBounds(TaskRecord task, Rect bounds) {
+    void updateBounds(Task task, Rect bounds) {
         if (bounds.isEmpty()) {
             return;
         }
@@ -2423,8 +2422,8 @@
         }
     }
 
-    private void addOrReparentStartingActivity(TaskRecord parent, String reason) {
-        if (mStartActivity.getTaskRecord() == null || mStartActivity.getTaskRecord() == parent) {
+    private void addOrReparentStartingActivity(Task parent, String reason) {
+        if (mStartActivity.getTask() == null || mStartActivity.getTask() == parent) {
             parent.addChild(mStartActivity);
         } else {
             mStartActivity.reparent(parent, parent.getChildCount() /* top */, reason);
@@ -2460,7 +2459,7 @@
 
     private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, int launchFlags,
             ActivityOptions aOptions) {
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
         if (stack != null) {
             return stack;
@@ -2542,7 +2541,7 @@
                 && (mPreferredDisplayId == focusedStack.mDisplayId);
     }
 
-    private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+    private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, Task task,
             ActivityOptions aOptions) {
         // We are reusing a task, keep the stack!
         if (mReuseTask != null) {
@@ -2753,7 +2752,7 @@
         return this;
     }
 
-    ActivityStarter setInTask(TaskRecord inTask) {
+    ActivityStarter setInTask(Task inTask) {
         mRequest.inTask = inTask;
         return this;
     }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index 0488a3b..cce005b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -229,7 +229,7 @@
     public abstract int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
             String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
             String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
-            int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+            int userId, Task inTask, String reason, boolean validateIncomingUser,
             PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart);
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 80232d3..3ef848c 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -117,9 +117,9 @@
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_ONLY;
 import static com.android.server.wm.RootActivityContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.REPARENT_KEEP_STACK_AT_FRONT;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.Task.REPARENT_KEEP_STACK_AT_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
 
 import android.Manifest;
 import android.annotation.IntDef;
@@ -1572,7 +1572,7 @@
                 return true;
             }
             // Keep track of the root activity of the task before we finish it
-            final TaskRecord tr = r.getTaskRecord();
+            final Task tr = r.getTask();
             final ActivityRecord rootR = tr.getRootActivity();
             if (rootR == null) {
                 Slog.w(TAG, "Finishing task with all activities already finished");
@@ -1994,7 +1994,7 @@
                 if (r == null) {
                     return false;
                 }
-                final TaskRecord task = r.getTaskRecord();
+                final Task task = r.getTask();
                 int index = task.mChildren.lastIndexOf(r);
                 if (index > 0) {
                     ActivityRecord under = task.getChildAt(index - 1);
@@ -2086,7 +2086,7 @@
         final long callingId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     return;
@@ -2196,7 +2196,7 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 int taskId = ActivityRecord.getTaskForActivityLocked(token, !nonRoot);
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+                final Task task = mRootActivityContainer.anyTaskForId(taskId);
                 if (task != null) {
                     return ActivityRecord.getStackLocked(token).moveTaskToBackLocked(taskId);
                 }
@@ -2214,7 +2214,7 @@
         Rect rect = new Rect();
         try {
             synchronized (mGlobalLock) {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
                 if (task == null) {
                     Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
@@ -2237,7 +2237,7 @@
         synchronized (mGlobalLock) {
             enforceCallerIsRecentsOrHasPermission(
                     MANAGE_ACTIVITY_STACKS, "getTaskDescription()");
-            final TaskRecord tr = mRootActivityContainer.anyTaskForId(id,
+            final Task tr = mRootActivityContainer.anyTaskForId(id,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (tr != null) {
                 return tr.getTaskDescription();
@@ -2257,7 +2257,7 @@
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "setTaskWindowingMode: No task for id=" + taskId);
@@ -2335,7 +2335,7 @@
                 // windows above full screen activities. Instead of directly finishing the
                 // task, a task change listener is used to notify SystemUI so the action can be
                 // handled specially.
-                final TaskRecord task = r.getTaskRecord();
+                final Task task = r.getTask();
                 mTaskChangeNotificationController
                         .notifyBackPressedOnTaskRoot(task.getTaskInfo());
             } else {
@@ -2393,7 +2393,7 @@
             }
         }
         try {
-            final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+            final Task task = mRootActivityContainer.anyTaskForId(taskId);
             if (task == null) {
                 Slog.d(TAG, "Could not find task for id: "+ taskId);
                 SafeActivityOptions.abort(options);
@@ -2573,7 +2573,7 @@
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+                final Task task = mRootActivityContainer.anyTaskForId(taskId);
                 if (task == null) {
                     Slog.w(TAG, "moveTaskToStack: No task for id=" + taskId);
                     return;
@@ -2619,7 +2619,7 @@
                     throw new IllegalArgumentException("Stack: " + stackId
                         + " doesn't support animated resize.");
                 }
-                stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+                stack.animateResizePinnedStack(destBounds, null /* sourceHintBounds */,
                         animationDuration, false /* fromFullscreen */);
             }
         } finally {
@@ -2654,7 +2654,7 @@
                     return;
                 }
                 destBounds.offset(xOffset, yOffset);
-                stack.animateResizePinnedStack(null /* sourceHintBounds */, destBounds,
+                stack.animateResizePinnedStack(destBounds, null /* sourceHintBounds */,
                         animationDuration, false /* fromFullscreen */);
             }
         } finally {
@@ -2685,7 +2685,7 @@
         synchronized (mGlobalLock) {
             final long ident = Binder.clearCallingIdentity();
             try {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "setTaskWindowingModeSplitScreenPrimary: No task for id=" + taskId);
@@ -2817,7 +2817,7 @@
             if (r == null) {
                 return;
             }
-            startLockTaskModeLocked(r.getTaskRecord(), false /* isSystemCaller */);
+            startLockTaskModeLocked(r.getTask(), false /* isSystemCaller */);
         }
     }
 
@@ -2828,7 +2828,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     return;
@@ -2850,7 +2850,7 @@
             if (r == null) {
                 return;
             }
-            stopLockTaskModeInternal(r.getTaskRecord(), false /* isSystemCaller */);
+            stopLockTaskModeInternal(r.getTask(), false /* isSystemCaller */);
         }
     }
 
@@ -2864,7 +2864,7 @@
         stopLockTaskModeInternal(null, true /* isSystemCaller */);
     }
 
-    private void startLockTaskModeLocked(@Nullable TaskRecord task, boolean isSystemCaller) {
+    private void startLockTaskModeLocked(@Nullable Task task, boolean isSystemCaller) {
         if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK, "startLockTaskModeLocked: " + task);
         if (task == null || task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
             return;
@@ -2893,7 +2893,7 @@
         }
     }
 
-    private void stopLockTaskModeInternal(@Nullable TaskRecord task, boolean isSystemCaller) {
+    private void stopLockTaskModeInternal(@Nullable Task task, boolean isSystemCaller) {
         final int callingUid = Binder.getCallingUid();
         long ident = Binder.clearCallingIdentity();
         try {
@@ -2943,7 +2943,7 @@
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
                 r.setTaskDescription(td);
-                final TaskRecord task = r.getTaskRecord();
+                final Task task = r.getTask();
                 task.updateTaskDescription();
             }
         }
@@ -2999,7 +2999,7 @@
     public boolean isTopOfTask(IBinder token) {
         synchronized (mGlobalLock) {
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
-            return r != null && r.getTaskRecord().getTopActivity() == r;
+            return r != null && r.getTask().getTopActivity() == r;
         }
     }
 
@@ -3038,7 +3038,7 @@
             }
             if (structure != null) {
                 // Pre-fill the task/activity component for all assist data receivers
-                structure.setTaskId(pae.activity.getTaskRecord().mTaskId);
+                structure.setTaskId(pae.activity.getTask().mTaskId);
                 structure.setActivityComponent(pae.activity.mActivityComponent);
                 structure.setHomeActivity(pae.isHome);
             }
@@ -3065,7 +3065,7 @@
                 // Caller wants result sent back to them.
                 sendBundle = new Bundle();
                 sendBundle.putInt(ActivityTaskManagerInternal.ASSIST_TASK_ID,
-                        pae.activity.getTaskRecord().mTaskId);
+                        pae.activity.getTask().mTaskId);
                 sendBundle.putBinder(ActivityTaskManagerInternal.ASSIST_ACTIVITY_ID,
                         pae.activity.assistToken);
                 sendBundle.putBundle(ASSIST_KEY_DATA, pae.extras);
@@ -3153,7 +3153,7 @@
                 }
 
                 final ActivityStack stack = r.getActivityStack();
-                final TaskRecord task = stack.createTaskRecord(
+                final Task task = stack.createTask(
                         mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), ainfo, intent,
                         null /* voiceSession */, null /* voiceInteractor */, !ON_TOP);
                 if (!mRecentTasks.addToBottom(task)) {
@@ -3182,7 +3182,7 @@
     @Override
     public void setTaskResizeable(int taskId, int resizeableMode) {
         synchronized (mGlobalLock) {
-            final TaskRecord task = mRootActivityContainer.anyTaskForId(
+            final Task task = mRootActivityContainer.anyTaskForId(
                     taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
@@ -3198,7 +3198,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
@@ -3243,7 +3243,7 @@
 
     private void sanitizeAndApplyConfigChange(ConfigurationContainer container,
             WindowContainerTransaction.Change change) {
-        if (!(container instanceof TaskRecord)) {
+        if (!(container instanceof Task)) {
             throw new RuntimeException("Invalid token in task transaction");
         }
         // The "client"-facing API should prevent bad changes; however, just in case, sanitize
@@ -3884,7 +3884,7 @@
             try {
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
                         + taskId + " in stackId=" + stackId + " at position=" + position);
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId);
+                final Task task = mRootActivityContainer.anyTaskForId(taskId);
                 if (task == null) {
                     throw new IllegalArgumentException("positionTaskInStack: no task for id="
                             + taskId);
@@ -3997,8 +3997,9 @@
                             + " doesn't support animated resize.");
                 }
                 if (animate) {
-                    stack.animateResizePinnedStack(null /* sourceHintBounds */,
-                            null /* destBounds */, animationDuration, false /* fromFullscreen */);
+                    stack.animateResizePinnedStack(null /* destBounds */,
+                            null /* sourceHintBounds */, animationDuration,
+                            false /* fromFullscreen */);
                 } else {
                     stack.dismissPip();
                 }
@@ -4103,7 +4104,7 @@
 
         // If we are animating to fullscreen then we have already dispatched the PIP mode
         // changed, so we should reflect that check here as well.
-        final TaskStack taskStack = r.getActivityStack().getTaskStack();
+        final ActivityStack taskStack = r.getActivityStack();
         return !taskStack.isAnimatingBoundsToFullscreen();
     }
 
@@ -4358,7 +4359,7 @@
             if (ActivityRecord.forTokenLocked(callingActivity) != activity) {
                 throw new SecurityException("Only focused activity can call startVoiceInteraction");
             }
-            if (mRunningVoice != null || activity.getTaskRecord().voiceSession != null
+            if (mRunningVoice != null || activity.getTask().voiceSession != null
                     || activity.voiceSession != null) {
                 Slog.w(TAG, "Already in a voice interaction, cannot start new voice interaction");
                 return;
@@ -4468,7 +4469,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                final TaskRecord task = mRootActivityContainer.anyTaskForId(taskId,
+                final Task task = mRootActivityContainer.anyTaskForId(taskId,
                         MATCH_TASK_IN_STACKS_ONLY);
                 if (task == null) {
                     Slog.w(TAG, "cancelTaskWindowTransition: taskId=" + taskId + " not found");
@@ -4494,7 +4495,7 @@
 
     private ActivityManager.TaskSnapshot getTaskSnapshot(int taskId, boolean reducedResolution,
             boolean restoreFromDisk) {
-        final TaskRecord task;
+        final Task task;
         synchronized (mGlobalLock) {
             task = mRootActivityContainer.anyTaskForId(taskId,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
@@ -4819,7 +4820,7 @@
     }
 
     /** Pokes the task persister. */
-    void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+    void notifyTaskPersisterLocked(Task task, boolean flush) {
         mRecentTasks.notifyTaskPersisterLocked(task, flush);
     }
 
@@ -4976,7 +4977,7 @@
         String[] newArgs = new String[args.length - opti];
         System.arraycopy(args, opti, newArgs, 0, args.length - opti);
 
-        TaskRecord lastTask = null;
+        Task lastTask = null;
         boolean needSep = false;
         for (int i = activities.size() - 1; i >= 0; i--) {
             ActivityRecord r = activities.get(i);
@@ -4985,7 +4986,7 @@
             }
             needSep = true;
             synchronized (mGlobalLock) {
-                final TaskRecord task = r.getTaskRecord();
+                final Task task = r.getTask();
                 if (lastTask != task) {
                     lastTask = task;
                     pw.print("TASK "); pw.print(lastTask.affinity);
@@ -5402,7 +5403,7 @@
 
     /** Update AMS states when an activity is resumed. */
     void setResumedActivityUncheckLocked(ActivityRecord r, String reason) {
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         if (task.isActivityTypeStandard()) {
             if (mCurAppTimeTracker != r.appTimeTracker) {
                 // We are switching app tracking.  Complete the current one.
@@ -5434,7 +5435,7 @@
             if (mLastResumedActivity != null) {
                 final IVoiceInteractionSession session;
 
-                final TaskRecord lastResumedActivityTask = mLastResumedActivity.getTaskRecord();
+                final Task lastResumedActivityTask = mLastResumedActivity.getTask();
                 if (lastResumedActivityTask != null
                         && lastResumedActivityTask.voiceSession != null) {
                     session = lastResumedActivityTask.voiceSession;
@@ -5535,7 +5536,7 @@
 
     void updateActivityUsageStats(ActivityRecord activity, int event) {
         ComponentName taskRoot = null;
-        final TaskRecord task = activity.getTaskRecord();
+        final Task task = activity.getTask();
         if (task != null) {
             final ActivityRecord rootActivity = task.getRootActivity();
             if (rootActivity != null) {
@@ -6140,7 +6141,7 @@
         public int startActivityInPackage(int uid, int realCallingPid, int realCallingUid,
                 String callingPackage, Intent intent, String resolvedType, IBinder resultTo,
                 String resultWho, int requestCode, int startFlags, SafeActivityOptions options,
-                int userId, TaskRecord inTask, String reason, boolean validateIncomingUser,
+                int userId, Task inTask, String reason, boolean validateIncomingUser,
                 PendingIntentRecord originatingPendingIntent,
                 boolean allowBackgroundActivityStart) {
             synchronized (mGlobalLock) {
@@ -6569,13 +6570,13 @@
         @Override
         public ActivityTokens getTopActivityForTask(int taskId) {
             synchronized (mGlobalLock) {
-                final TaskRecord taskRecord = mRootActivityContainer.anyTaskForId(taskId);
-                if (taskRecord == null) {
+                final Task task = mRootActivityContainer.anyTaskForId(taskId);
+                if (task == null) {
                     Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
                             + " Requested task not found");
                     return null;
                 }
-                final ActivityRecord activity = taskRecord.getTopActivity();
+                final ActivityRecord activity = task.getTopActivity();
                 if (activity == null) {
                     Slog.w(TAG, "getApplicationThreadForTopActivity failed:"
                             + " Requested activity not found");
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index c5e190d..93a22ca 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -79,12 +79,12 @@
         synchronized (mService.mGlobalLock) {
             long origId = Binder.clearCallingIdentity();
             try {
-                TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+                Task task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
                         MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
-                if (tr == null) {
+                if (task == null) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
-                return mService.getRecentTasks().createRecentTaskInfo(tr);
+                return mService.getRecentTasks().createRecentTaskInfo(task);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -136,12 +136,12 @@
         checkCaller();
 
         int callingUser = UserHandle.getCallingUserId();
-        TaskRecord tr;
+        Task task;
         IApplicationThread appThread;
         synchronized (mService.mGlobalLock) {
-            tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+            task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
-            if (tr == null) {
+            if (task == null) {
                 throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
             }
             appThread = IApplicationThread.Stub.asInterface(whoThread);
@@ -156,7 +156,7 @@
                 .setResolvedType(resolvedType)
                 .setActivityOptions(bOptions)
                 .setUserId(callingUser)
-                .setInTask(tr)
+                .setInTask(task)
                 .execute();
     }
 
@@ -167,12 +167,12 @@
         synchronized (mService.mGlobalLock) {
             long origId = Binder.clearCallingIdentity();
             try {
-                TaskRecord tr = mService.mRootActivityContainer.anyTaskForId(mTaskId,
+                Task task = mService.mRootActivityContainer.anyTaskForId(mTaskId,
                         MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);
-                if (tr == null) {
+                if (task == null) {
                     throw new IllegalArgumentException("Unable to find task ID " + mTaskId);
                 }
-                Intent intent = tr.getBaseIntent();
+                Intent intent = task.getBaseIntent();
                 if (exclude) {
                     intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 } else {
diff --git a/services/core/java/com/android/server/wm/BarController.java b/services/core/java/com/android/server/wm/BarController.java
index 5c4332d..05d5a5c 100644
--- a/services/core/java/com/android/server/wm/BarController.java
+++ b/services/core/java/com/android/server/wm/BarController.java
@@ -146,8 +146,7 @@
 
     int applyTranslucentFlagLw(WindowState win, int vis, int oldVis) {
         if (mWin != null) {
-            if (win != null && (win.getAttrs().privateFlags
-                    & WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) == 0) {
+            if (win != null) {
                 int fl = PolicyControl.getWindowFlags(win, null);
                 if ((fl & mTranslucentWmFlag) != 0) {
                     vis |= mTranslucentFlag;
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 d1d468b..b4dd55d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -556,9 +556,9 @@
     // Last systemUiVisibility we dispatched to windows.
     private int mLastDispatchedSystemUiVisibility = 0;
 
-    private final ArrayList<TaskStack> mTmpAlwaysOnTopStacks = new ArrayList<>();
-    private final ArrayList<TaskStack> mTmpNormalStacks = new ArrayList<>();
-    private final ArrayList<TaskStack> mTmpHomeStacks = new ArrayList<>();
+    private final ArrayList<ActivityStack> mTmpAlwaysOnTopStacks = new ArrayList<>();
+    private final ArrayList<ActivityStack> mTmpNormalStacks = new ArrayList<>();
+    private final ArrayList<ActivityStack> mTmpHomeStacks = new ArrayList<>();
 
     /** Corner radius that windows should have in order to match the display. */
     private final float mWindowCornerRadius;
@@ -937,6 +937,8 @@
         super.addChild(mTaskStackContainers, null);
         super.addChild(mAboveAppWindowsContainers, null);
         super.addChild(mImeWindowsContainers, null);
+        // Sets the display content for the children.
+        onDisplayChanged(this);
 
         // Add itself as a child to the root container.
         mWmService.mRoot.addChild(this, null);
@@ -1171,6 +1173,9 @@
         if (!isReady() || mActivityDisplay == null) {
             return;
         }
+        if (mDisplayRotation.isWaitingForRemoteRotation()) {
+            return;
+        }
         final boolean configUpdated = mActivityDisplay.updateDisplayOverrideConfigurationLocked();
         if (configUpdated) {
             return;
@@ -1796,15 +1801,15 @@
         return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
     }
 
-    TaskStack getHomeStack() {
+    ActivityStack getHomeStack() {
         return mTaskStackContainers.getHomeStack();
     }
 
     /**
      * @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise.
      */
-    TaskStack getSplitScreenPrimaryStack() {
-        TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStack();
+    ActivityStack getSplitScreenPrimaryStack() {
+        ActivityStack stack = mTaskStackContainers.getSplitScreenPrimaryStack();
         return (stack != null && stack.isVisible()) ? stack : null;
     }
 
@@ -1816,11 +1821,11 @@
      * Like {@link #getSplitScreenPrimaryStack}, but also returns the stack if it's currently
      * not visible.
      */
-    TaskStack getSplitScreenPrimaryStackIgnoringVisibility() {
+    ActivityStack getSplitScreenPrimaryStackIgnoringVisibility() {
         return mTaskStackContainers.getSplitScreenPrimaryStack();
     }
 
-    TaskStack getPinnedStack() {
+    ActivityStack getPinnedStack() {
         return mTaskStackContainers.getPinnedStack();
     }
 
@@ -1832,7 +1837,7 @@
      * Returns the topmost stack on the display that is compatible with the input windowing mode.
      * Null is no compatible stack on the display.
      */
-    TaskStack getTopStackInWindowingMode(int windowingMode) {
+    ActivityStack getTopStackInWindowingMode(int windowingMode) {
         return getStack(windowingMode, ACTIVITY_TYPE_UNDEFINED);
     }
 
@@ -1840,17 +1845,17 @@
      * Returns the topmost stack on the display that is compatible with the input windowing mode and
      * activity type. Null is no compatible stack on the display.
      */
-    TaskStack getStack(int windowingMode, int activityType) {
+    ActivityStack getStack(int windowingMode, int activityType) {
         return mTaskStackContainers.getStack(windowingMode, activityType);
     }
 
     @VisibleForTesting
-    WindowList<TaskStack> getStacks() {
+    WindowList<ActivityStack> getStacks() {
         return mTaskStackContainers.mChildren;
     }
 
     @VisibleForTesting
-    TaskStack getTopStack() {
+    ActivityStack getTopStack() {
         return mTaskStackContainers.getTopStack();
     }
 
@@ -1858,7 +1863,7 @@
         return mTaskStackContainers.getVisibleTasks();
     }
 
-    void onStackWindowingModeChanged(TaskStack stack) {
+    void onStackWindowingModeChanged(ActivityStack stack) {
         mTaskStackContainers.onStackWindowingModeChanged(stack);
     }
 
@@ -2202,27 +2207,18 @@
         out.set(mDisplayFrames.mStable);
     }
 
-    void setStackOnDisplay(int stackId, boolean onTop, TaskStack stack) {
-        if (DEBUG_STACK) {
-            Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId=" + mDisplayId);
-        }
-
-        mTaskStackContainers.addStackToDisplay(stack, onTop);
+    void setStackOnDisplay(ActivityStack stack, int position) {
+        if (DEBUG_STACK) Slog.d(TAG_WM, "Set stack=" + stack + " on displayId=" + mDisplayId);
+        mTaskStackContainers.addChild(stack, position);
     }
 
-    void moveStackToDisplay(TaskStack stack, boolean onTop) {
-        final DisplayContent prevDc = stack.getDisplayContent();
-        if (prevDc == null) {
-            throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
-                    + " which is not currently attached to any display");
-        }
-        if (prevDc.getDisplayId() == mDisplayId) {
-            throw new IllegalArgumentException("Trying to move stackId=" + stack.mStackId
-                    + " to its current displayId=" + mDisplayId);
-        }
+    void moveStackToDisplay(ActivityStack stack, boolean onTop) {
+        stack.reparent(mTaskStackContainers, onTop ? POSITION_TOP: POSITION_BOTTOM);
+    }
 
-        prevDc.mTaskStackContainers.removeChild(stack);
-        mTaskStackContainers.addStackToDisplay(stack, onTop);
+    // TODO(display-unify): No longer needed then.
+    void removeStackFromDisplay(ActivityStack stack) {
+        mTaskStackContainers.removeChild(stack);
     }
 
     @Override
@@ -2254,7 +2250,7 @@
         getParent().positionChildAt(position, this, includingParents);
     }
 
-    void positionStackAt(int position, TaskStack child, boolean includingParents) {
+    void positionStackAt(int position, ActivityStack child, boolean includingParents) {
         mTaskStackContainers.positionChildAt(position, child, includingParents);
         layoutAndAssignWindowLayersIfNeeded();
     }
@@ -2264,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;
             }
@@ -2275,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;
     }
@@ -2288,7 +2284,7 @@
         final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
         mTmpTaskForResizePointSearchResult.reset();
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
             if (!stack.getWindowConfiguration().canResizeTask()) {
                 return null;
             }
@@ -2311,7 +2307,7 @@
             mTmpRect2.setEmpty();
             for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0;
                     --stackNdx) {
-                final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+                final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
                 stack.setTouchExcludeRegion(focusedTask, delta, mTouchExcludeRegion,
                         mDisplayFrames.mContent, mTmpRect2);
             }
@@ -2357,8 +2353,8 @@
     }
 
     @Override
-    void switchUser() {
-        super.switchUser();
+    void switchUser(int userId) {
+        super.switchUser(userId);
         mWmService.mWindowsChanged = true;
         mDisplayPolicy.switchUser();
     }
@@ -2398,6 +2394,7 @@
             mWindowingLayer.release();
             mOverlayLayer.release();
             mInputMonitor.onDisplayRemoved();
+            mWmService.mDisplayNotificationController.dispatchDisplayRemoved(mActivityDisplay);
         } finally {
             mDisplayReady = false;
             mRemovingDisplay = false;
@@ -2440,7 +2437,7 @@
         boolean updated = false;
 
         for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(i);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(i);
             if (stack == null || !stack.isAdjustedForIme()) {
                 continue;
             }
@@ -2469,7 +2466,7 @@
     boolean clearImeAdjustAnimation() {
         boolean changed = false;
         for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(i);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(i);
             if (stack != null && stack.isAdjustedForIme()) {
                 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                 changed  = true;
@@ -2480,7 +2477,7 @@
 
     void beginImeAdjustAnimation() {
         for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(i);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(i);
             if (stack.isVisible() && stack.isAdjustedForIme()) {
                 stack.beginImeAdjustAnimation();
             }
@@ -2491,10 +2488,10 @@
         final WindowState imeWin = mInputMethodWindow;
         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
                 && !mDividerControllerLocked.isImeHideRequested();
-        final TaskStack dockedStack = getSplitScreenPrimaryStack();
+        final ActivityStack dockedStack = getSplitScreenPrimaryStack();
         final boolean dockVisible = dockedStack != null;
         final Task topDockedTask = dockVisible ? dockedStack.getTopChild() : null;
-        final TaskStack imeTargetStack = mWmService.getImeFocusStackLocked();
+        final ActivityStack imeTargetStack = mWmService.getImeFocusStackLocked();
         final int imeDockSide = (dockVisible && imeTargetStack != null) ?
                 imeTargetStack.getDockSide() : DOCKED_INVALID;
         final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
@@ -2518,7 +2515,7 @@
 
         if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
             for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-                final TaskStack stack = mTaskStackContainers.getChildAt(i);
+                final ActivityStack stack = mTaskStackContainers.getChildAt(i);
                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
                 if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)
                         && stack.inSplitScreenWindowingMode()) {
@@ -2531,7 +2528,7 @@
                     imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
         } else {
             for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-                final TaskStack stack = mTaskStackContainers.getChildAt(i);
+                final ActivityStack stack = mTaskStackContainers.getChildAt(i);
                 stack.resetAdjustedForIme(!dockVisible);
             }
             mDividerControllerLocked.setAdjustedForIme(
@@ -2542,7 +2539,7 @@
 
     void prepareFreezingTaskBounds() {
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
             stack.prepareFreezingTaskBounds();
         }
     }
@@ -2623,8 +2620,8 @@
         super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
         proto.write(ID, mDisplayId);
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
-            stack.writeToProto(proto, STACKS, logLevel);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
+            stack.writeToProtoInnerStackOnly(proto, STACKS, logLevel);
         }
         mDividerControllerLocked.writeToProto(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
         mPinnedStackControllerLocked.writeToProto(proto, PINNED_STACK_CONTROLLER);
@@ -2738,7 +2735,7 @@
         pw.println();
         pw.println(prefix + "Application tokens in top down Z order:");
         for (int stackNdx = mTaskStackContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
-            final TaskStack stack = mTaskStackContainers.getChildAt(stackNdx);
+            final ActivityStack stack = mTaskStackContainers.getChildAt(stackNdx);
             stack.dump(pw, prefix + "  ", dumpAll);
         }
 
@@ -2768,15 +2765,15 @@
         pw.println();
 
         // Dump stack references
-        final TaskStack homeStack = getHomeStack();
+        final ActivityStack homeStack = getHomeStack();
         if (homeStack != null) {
             pw.println(prefix + "homeStack=" + homeStack.getName());
         }
-        final TaskStack pinnedStack = getPinnedStack();
+        final ActivityStack pinnedStack = getPinnedStack();
         if (pinnedStack != null) {
             pw.println(prefix + "pinnedStack=" + pinnedStack.getName());
         }
-        final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
+        final ActivityStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
         if (splitScreenPrimaryStack != null) {
             pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
         }
@@ -2809,7 +2806,7 @@
 
     /** Returns true if the stack in the windowing mode is visible. */
     boolean isStackVisible(int windowingMode) {
-        final TaskStack stack = getTopStackInWindowingMode(windowingMode);
+        final ActivityStack stack = getTopStackInWindowingMode(windowingMode);
         return stack != null && stack.isVisible();
     }
 
@@ -3914,7 +3911,7 @@
      * Window container class that contains all containers on this display relating to Apps.
      * I.e Activities.
      */
-    private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
+    private final class TaskStackContainers extends DisplayChildWindowContainer<ActivityStack> {
         /**
          * A control placed at the appropriate level for transitions to occur.
          */
@@ -3939,19 +3936,25 @@
 
         // Cached reference to some special stacks we tend to get a lot so we don't need to loop
         // through the list to find them.
-        private TaskStack mHomeStack = null;
-        private TaskStack mPinnedStack = null;
-        private TaskStack mSplitScreenPrimaryStack = null;
+        private ActivityStack mHomeStack = null;
+        private ActivityStack mPinnedStack = null;
+        private ActivityStack mSplitScreenPrimaryStack = null;
 
         TaskStackContainers(WindowManagerService service) {
             super(service);
         }
 
+        @Override
+        public void onConfigurationChanged(Configuration newParentConfig) {
+            // TODO(display-unify): Remove after unification.
+            onConfigurationChanged(newParentConfig, mActivityDisplay == null /*forwardToChildren*/);
+        }
+
         /**
          * Returns the topmost stack on the display that is compatible with the input windowing mode
          * and activity type. Null is no compatible stack on the display.
          */
-        TaskStack getStack(int windowingMode, int activityType) {
+        ActivityStack getStack(int windowingMode, int activityType) {
             if (activityType == ACTIVITY_TYPE_HOME) {
                 return mHomeStack;
             }
@@ -3961,7 +3964,7 @@
                 return mSplitScreenPrimaryStack;
             }
             for (int i = mTaskStackContainers.getChildCount() - 1; i >= 0; --i) {
-                final TaskStack stack = mTaskStackContainers.getChildAt(i);
+                final ActivityStack stack = mTaskStackContainers.getChildAt(i);
                 if (activityType == ACTIVITY_TYPE_UNDEFINED
                         && windowingMode == stack.getWindowingMode()) {
                     // Passing in undefined type means we want to match the topmost stack with the
@@ -3976,23 +3979,23 @@
         }
 
         @VisibleForTesting
-        TaskStack getTopStack() {
+        ActivityStack getTopStack() {
             return mTaskStackContainers.getChildCount() > 0
                     ? mTaskStackContainers.getChildAt(mTaskStackContainers.getChildCount() - 1) : null;
         }
 
-        TaskStack getHomeStack() {
+        ActivityStack getHomeStack() {
             if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
                 Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
             }
             return mHomeStack;
         }
 
-        TaskStack getPinnedStack() {
+        ActivityStack getPinnedStack() {
             return mPinnedStack;
         }
 
-        TaskStack getSplitScreenPrimaryStack() {
+        ActivityStack getSplitScreenPrimaryStack() {
             return mSplitScreenPrimaryStack;
         }
 
@@ -4006,16 +4009,7 @@
             return visibleTasks;
         }
 
-        /**
-         * Adds the stack to this container.
-         */
-        void addStackToDisplay(TaskStack stack, boolean onTop) {
-            addStackReferenceIfNeeded(stack);
-            addChild(stack, onTop);
-            stack.onDisplayChanged(DisplayContent.this);
-        }
-
-        void onStackWindowingModeChanged(TaskStack stack) {
+        void onStackWindowingModeChanged(ActivityStack stack) {
             removeStackReferenceIfNeeded(stack);
             addStackReferenceIfNeeded(stack);
             if (stack == mPinnedStack && getTopStack() != stack) {
@@ -4024,7 +4018,7 @@
             }
         }
 
-        private void addStackReferenceIfNeeded(TaskStack stack) {
+        private void addStackReferenceIfNeeded(ActivityStack stack) {
             if (stack.isActivityTypeHome()) {
                 if (mHomeStack != null) {
                     throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
@@ -4052,7 +4046,7 @@
             }
         }
 
-        private void removeStackReferenceIfNeeded(TaskStack stack) {
+        private void removeStackReferenceIfNeeded(ActivityStack stack) {
             if (stack == mHomeStack) {
                 mHomeStack = null;
             } else if (stack == mPinnedStack) {
@@ -4066,16 +4060,29 @@
             }
         }
 
-        private void addChild(TaskStack stack, boolean toTop) {
-            final int addIndex = findPositionForStack(toTop ? mChildren.size() : 0, stack,
-                    true /* adding */);
-            addChild(stack, addIndex);
-            setLayoutNeeded();
+        @Override
+        void addChild(ActivityStack stack, int position) {
+            addStackReferenceIfNeeded(stack);
+            position = findPositionForStack(position, stack, true /* adding */);
+
+            super.addChild(stack, position);
+            if (mActivityDisplay != null) {
+                mActivityDisplay.addChild(stack, position, true /*fromDc*/);
+            }
+
+            // The reparenting case is handled in WindowContainer.
+            if (!stack.mReparenting) {
+                setLayoutNeeded();
+                stack.onDisplayChanged(DisplayContent.this);
+            }
         }
 
         @Override
-        protected void removeChild(TaskStack stack) {
+        protected void removeChild(ActivityStack stack) {
             super.removeChild(stack);
+            if (mActivityDisplay != null) {
+                mActivityDisplay.onChildRemoved(stack);
+            }
             removeStackReferenceIfNeeded(stack);
         }
 
@@ -4086,7 +4093,7 @@
         }
 
         @Override
-        void positionChildAt(int position, TaskStack child, boolean includingParents) {
+        void positionChildAt(int position, ActivityStack child, boolean includingParents) {
             if (child.getWindowConfiguration().isAlwaysOnTop()
                     && position != POSITION_TOP) {
                 // This stack is always-on-top, override the default behavior.
@@ -4125,7 +4132,8 @@
          * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
          * @return The proper position for the stack.
          */
-        private int findPositionForStack(int requestedPosition, TaskStack stack, boolean adding) {
+        private int findPositionForStack(int requestedPosition, ActivityStack stack,
+                boolean adding) {
             if (stack.inPinnedWindowingMode()) {
                 return POSITION_TOP;
             }
@@ -4162,6 +4170,14 @@
             targetPosition = Math.min(targetPosition, maxPosition);
             targetPosition = Math.max(targetPosition, minPosition);
 
+            // Cap the requested position to something reasonable for the previous position check
+            // below.
+            if (requestedPosition == POSITION_TOP) {
+                requestedPosition = mChildren.size();
+            } else if (requestedPosition == POSITION_BOTTOM) {
+                requestedPosition = 0;
+            }
+
             int prevPosition = getStacks().indexOf(stack);
             // The positions we calculated above (maxPosition, minPosition) do not take into
             // consideration the following edge cases.
@@ -4299,7 +4315,7 @@
             assignStackOrdering(t);
 
             for (int i = 0; i < mChildren.size(); i++) {
-                final TaskStack s = mChildren.get(i);
+                final ActivityStack s = mChildren.get(i);
                 s.assignChildLayers(t);
             }
         }
@@ -4312,7 +4328,7 @@
             mTmpHomeStacks.clear();
             mTmpNormalStacks.clear();
             for (int i = 0; i < mChildren.size(); ++i) {
-                final TaskStack s = mChildren.get(i);
+                final ActivityStack s = mChildren.get(i);
                 if (s.isAlwaysOnTop()) {
                     mTmpAlwaysOnTopStacks.add(s);
                 } else if (s.isActivityTypeHome()) {
@@ -4332,7 +4348,7 @@
             int layerForSplitScreenDividerAnchor = layer++;
             int layerForAnimationLayer = layer++;
             for (int i = 0; i < mTmpNormalStacks.size(); i++) {
-                final TaskStack s = mTmpNormalStacks.get(i);
+                final ActivityStack s = mTmpNormalStacks.get(i);
                 s.assignLayer(t, layer++);
                 if (s.inSplitScreenWindowingMode()) {
                     // The split screen divider anchor is located above the split screen window.
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 fcfd9de..f8c1ad9 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -56,7 +56,6 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
@@ -164,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;
@@ -295,9 +293,6 @@
 
     private boolean mIsFreeformWindowOverlappingWithNavBar;
 
-    /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
-    @Px private int mWindowOutsetBottom;
-
     private final StatusBarController mStatusBarController;
 
     private final BarController mNavigationBarController;
@@ -1210,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)}.
@@ -1218,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
@@ -1269,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;
             }
@@ -1313,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() {
@@ -1483,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();
@@ -1531,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,
@@ -1545,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.
@@ -1631,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);
@@ -1654,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);
@@ -1677,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);
@@ -1700,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());
@@ -1714,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'
@@ -1726,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
@@ -1756,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
@@ -1771,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
@@ -1821,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);
@@ -1832,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;
@@ -1861,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;
                 }
             }
 
@@ -1898,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) {
@@ -1912,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);
@@ -1936,13 +1890,11 @@
             }
         } else {
             dcf.set(displayFrames.mSystem);
-            final boolean inheritTranslucentDecor =
-                    (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
             final boolean isAppWindow =
                     type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
             final boolean topAtRest =
                     win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
-            if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
+            if (isAppWindow && !topAtRest) {
                 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
                         && (fl & FLAG_FULLSCREEN) == 0
                         && (fl & FLAG_TRANSLUCENT_STATUS) == 0
@@ -1970,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) {
@@ -1980,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
@@ -2006,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) {
@@ -2056,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);
@@ -2076,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
@@ -2108,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);
 
@@ -2126,7 +2049,6 @@
                     }
                 } else {
                     cf.set(displayFrames.mRestricted);
-                    of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
                 }
@@ -2143,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()
@@ -2155,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) {
@@ -2255,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;
             }
         }
 
@@ -2291,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);
@@ -2314,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) {
@@ -2725,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/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b454922..07d5094 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -140,7 +140,7 @@
     float mLastDividerProgress;
     private final DividerSnapAlgorithm[] mSnapAlgorithmForRotation = new DividerSnapAlgorithm[4];
     private boolean mImeHideRequested;
-    private TaskStack mDimmedStack;
+    private ActivityStack mDimmedStack;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -255,7 +255,7 @@
     }
 
     boolean isHomeStackResizable() {
-        final TaskStack homeStack = mDisplayContent.getHomeStack();
+        final ActivityStack homeStack = mDisplayContent.getHomeStack();
         if (homeStack == null) {
             return false;
         }
@@ -371,7 +371,7 @@
         if (mWindow == null) {
             return;
         }
-        TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
 
         // If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
         final boolean visible = stack != null;
@@ -415,7 +415,7 @@
     }
 
     void positionDockedStackedDivider(Rect frame) {
-        TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
         if (stack == null) {
             // Unfortunately we might end up with still having a divider, even though the underlying
             // stack was already removed. This is because we are on AM thread and the removal of the
@@ -523,7 +523,8 @@
 
             // If a primary stack was just created, it will not have access to display content at
             // this point so pass it from here to get a valid dock side.
-            final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+            final ActivityStack stack =
+                    mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
             mOriginalDockedSide = stack.getDockSideForDisplay(mDisplayContent);
             return;
         }
@@ -558,7 +559,7 @@
             boolean isHomeStackResizable) {
         long animDuration = 0;
         if (animate) {
-            final TaskStack stack =
+            final ActivityStack stack =
                     mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
             final long transitionDuration = isAnimationMaximizing()
                     ? mDisplayContent.mAppTransition.getLastClipRevealTransitionDuration()
@@ -629,10 +630,10 @@
      */
     void setResizeDimLayer(boolean visible, int targetWindowingMode, float alpha) {
         // TODO: Maybe only allow split-screen windowing modes?
-        final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
+        final ActivityStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
                 ? mDisplayContent.getTopStackInWindowingMode(targetWindowingMode)
                 : null;
-        final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
+        final ActivityStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
         boolean visibleAndValid = visible && stack != null && dockedStack != null;
 
         // Ensure an old dim that was shown for the docked stack divider is removed so we don't end
@@ -703,7 +704,7 @@
         if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
             return;
         }
-        final TaskStack homeStack = mDisplayContent.getHomeStack();
+        final ActivityStack homeStack = mDisplayContent.getHomeStack();
         if (homeStack == null) {
             return;
         }
@@ -717,7 +718,7 @@
         if (mMinimizedDock && mService.mKeyguardOrAodShowingOnDefaultDisplay) {
             return;
         }
-        final TaskStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
+        final ActivityStack topSecondaryStack = mDisplayContent.getTopStackInWindowingMode(
                 WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
         final RecentsAnimationController recentsAnim = mService.getRecentsAnimationController();
         final boolean minimizedForRecentsAnimation = recentsAnim != null &&
@@ -872,7 +873,7 @@
     }
 
     private boolean setMinimizedDockedStack(boolean minimized) {
-        final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        final ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
         notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
         return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
     }
@@ -922,7 +923,7 @@
     }
 
     private boolean animateForMinimizedDockedStack(long now) {
-        final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        final ActivityStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
         if (!mAnimationStarted) {
             mAnimationStarted = true;
             mAnimationStartTime = now;
@@ -956,7 +957,7 @@
     /**
      * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
      */
-    private float getMinimizeAmount(TaskStack stack, float t) {
+    private float getMinimizeAmount(ActivityStack stack, float t) {
         final float naturalAmount = getInterpolatedAnimationValue(t);
         if (isAnimationMaximizing()) {
             return adjustMaximizeAmount(stack, t, naturalAmount);
@@ -971,7 +972,7 @@
      * transition so we don't create a visible "hole", but only if both the clip reveal and the
      * docked stack divider start from about the same portion on the screen.
      */
-    private float adjustMaximizeAmount(TaskStack stack, float t, float naturalAmount) {
+    private float adjustMaximizeAmount(ActivityStack stack, float t, float naturalAmount) {
         if (mMaximizeMeetFraction == 1f) {
             return naturalAmount;
         }
@@ -987,7 +988,7 @@
      * Retrieves the animation fraction at which the docked stack has to meet the clip reveal
      * edge. See {@link #adjustMaximizeAmount}.
      */
-    private float getClipRevealMeetFraction(TaskStack stack) {
+    private float getClipRevealMeetFraction(ActivityStack stack) {
         if (!isAnimationMaximizing() || stack == null ||
                 !mDisplayContent.mAppTransition.hadClipRevealAnimation()) {
             return 1f;
diff --git a/services/core/java/com/android/server/wm/DragResizeMode.java b/services/core/java/com/android/server/wm/DragResizeMode.java
index c0bf1e8..71beb50 100644
--- a/services/core/java/com/android/server/wm/DragResizeMode.java
+++ b/services/core/java/com/android/server/wm/DragResizeMode.java
@@ -35,7 +35,7 @@
      */
     static final int DRAG_RESIZE_MODE_DOCKED_DIVIDER = 1;
 
-    static boolean isModeAllowedForStack(TaskStack stack, int mode) {
+    static boolean isModeAllowedForStack(ActivityStack stack, int mode) {
         switch (mode) {
             case DRAG_RESIZE_MODE_FREEFORM:
                 return stack.getWindowingMode() == WINDOWING_MODE_FREEFORM;
diff --git a/services/core/java/com/android/server/wm/LaunchParamsController.java b/services/core/java/com/android/server/wm/LaunchParamsController.java
index 6de48d1..03e1322 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsController.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsController.java
@@ -67,14 +67,14 @@
 
     /**
      * Returns the {@link LaunchParams} calculated by the registered modifiers
-     * @param task      The {@link TaskRecord} currently being positioned.
+     * @param task      The {@link Task} currently being positioned.
      * @param layout    The specified {@link WindowLayout}.
      * @param activity  The {@link ActivityRecord} currently being positioned.
      * @param source    The {@link ActivityRecord} from which activity was started from.
      * @param options   The {@link ActivityOptions} specified for the activity.
      * @param result    The resulting params.
      */
-    void calculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+    void calculate(Task task, WindowLayout layout, ActivityRecord activity,
                    ActivityRecord source, ActivityOptions options, int phase, LaunchParams result) {
         result.reset();
 
@@ -120,11 +120,11 @@
      * A convenience method for laying out a task.
      * @return {@code true} if bounds were set on the task. {@code false} otherwise.
      */
-    boolean layoutTask(TaskRecord task, WindowLayout layout) {
+    boolean layoutTask(Task task, WindowLayout layout) {
         return layoutTask(task, layout, null /*activity*/, null /*source*/, null /*options*/);
     }
 
-    boolean layoutTask(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+    boolean layoutTask(Task task, WindowLayout layout, ActivityRecord activity,
             ActivityRecord source, ActivityOptions options) {
         calculate(task, layout, activity, source, options, PHASE_BOUNDS, mTmpParams);
 
@@ -184,7 +184,7 @@
         /** The bounds within the parent container. */
         final Rect mBounds = new Rect();
 
-        /** The id of the display the {@link TaskRecord} would prefer to be on. */
+        /** The id of the display the {@link Task} would prefer to be on. */
         int mPreferredDisplayId;
 
         /** The windowing mode to be in. */
@@ -304,7 +304,7 @@
          * @return see {@link LaunchParamsModifier.Result}
          */
         @Result
-        int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+        int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
                 ActivityRecord source, ActivityOptions options, @Phase int phase,
                 LaunchParams currentParams, LaunchParams outParams);
     }
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 5d27390..c3bcc74 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -55,7 +55,7 @@
 /**
  * Persister that saves launch parameters in memory and in storage. It saves the last seen state of
  * tasks key-ed on task's user ID and the activity used to launch the task ({@link
- * TaskRecord#realActivity}) and that's used to determine the launch params when the activity is
+ * Task#realActivity}) and that's used to determine the launch params when the activity is
  * being launched again in {@link LaunchParamsController}.
  *
  * Need to hold {@link ActivityTaskManagerService#getGlobalLock()} to access this class.
@@ -196,7 +196,7 @@
         }
     }
 
-    void saveTask(TaskRecord task) {
+    void saveTask(Task task) {
         final ComponentName name = task.realActivity;
         final int userId = task.mUserId;
         PersistableLaunchParams params;
@@ -220,7 +220,7 @@
         }
     }
 
-    private boolean saveTaskToLaunchParam(TaskRecord task, PersistableLaunchParams params) {
+    private boolean saveTaskToLaunchParam(Task task, PersistableLaunchParams params) {
         final ActivityStack stack = task.getStack();
         final int displayId = stack.mDisplayId;
         final ActivityDisplay display =
@@ -245,7 +245,7 @@
         return changed;
     }
 
-    void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams outParams) {
+    void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) {
         final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
         final int userId = task != null ? task.mUserId : activity.mUserId;
 
@@ -412,7 +412,7 @@
         /** The bounds within the parent container. */
         final Rect mBounds = new Rect();
 
-        /** The unique id of the display the {@link TaskRecord} would prefer to be on. */
+        /** The unique id of the display the {@link Task} would prefer to be on. */
         String mDisplayUniqueId;
 
         /** The windowing mode to be in. */
diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java
index dc45686..6810f8c 100644
--- a/services/core/java/com/android/server/wm/LockTaskController.java
+++ b/services/core/java/com/android/server/wm/LockTaskController.java
@@ -32,11 +32,11 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.wm.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.wm.Task.LOCK_TASK_AUTH_WHITELISTED;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -157,7 +157,7 @@
      *
      * The list is empty if LockTask is inactive.
      */
-    private final ArrayList<TaskRecord> mLockTaskModeTasks = new ArrayList<>();
+    private final ArrayList<Task> mLockTaskModeTasks = new ArrayList<>();
 
     /**
      * Packages that are allowed to be launched into the lock task mode for each user.
@@ -221,14 +221,14 @@
      * back of the stack.
      */
     @VisibleForTesting
-    boolean isTaskLocked(TaskRecord task) {
+    boolean isTaskLocked(Task task) {
         return mLockTaskModeTasks.contains(task);
     }
 
     /**
      * @return {@code true} whether this task first started the current LockTask session.
      */
-    private boolean isRootTask(TaskRecord task) {
+    private boolean isRootTask(Task task) {
         return mLockTaskModeTasks.indexOf(task) == 0;
     }
 
@@ -237,7 +237,7 @@
      * of the last locked task and finishing it would mean that lock task mode is ended illegally.
      */
     boolean activityBlockedFromFinish(ActivityRecord activity) {
-        final TaskRecord task = activity.getTaskRecord();
+        final Task task = activity.getTask();
         if (activity == task.getRootActivity()
                 && activity == task.getTopActivity()
                 && task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV
@@ -254,7 +254,7 @@
      * {@link ActivityStack#moveTaskToBackLocked(int)}
      * @see #mLockTaskModeTasks
      */
-    boolean canMoveTaskToBack(TaskRecord task) {
+    boolean canMoveTaskToBack(Task task) {
         if (isRootTask(task)) {
             showLockTaskToast();
             return false;
@@ -266,7 +266,7 @@
      * @return whether the requested task is allowed to be locked (either whitelisted, or declares
      * lockTaskMode="always" in the manifest).
      */
-    boolean isTaskWhitelisted(TaskRecord task) {
+    boolean isTaskWhitelisted(Task task) {
         switch(task.mLockTaskAuth) {
             case LOCK_TASK_AUTH_WHITELISTED:
             case LOCK_TASK_AUTH_LAUNCHABLE:
@@ -282,7 +282,7 @@
     /**
      * @return whether the requested task is disallowed to be launched.
      */
-    boolean isLockTaskModeViolation(TaskRecord task) {
+    boolean isLockTaskModeViolation(Task task) {
         return isLockTaskModeViolation(task, false);
     }
 
@@ -290,7 +290,7 @@
      * @param isNewClearTask whether the task would be cleared as part of the operation.
      * @return whether the requested task is disallowed to be launched.
      */
-    boolean isLockTaskModeViolation(TaskRecord task, boolean isNewClearTask) {
+    boolean isLockTaskModeViolation(Task task, boolean isNewClearTask) {
         if (isLockTaskModeViolationInternal(task, isNewClearTask)) {
             showLockTaskToast();
             return true;
@@ -301,14 +301,14 @@
     /**
      * @return the root task of the lock task.
      */
-    TaskRecord getRootTask() {
+    Task getRootTask() {
         if (mLockTaskModeTasks.isEmpty()) {
             return null;
         }
         return mLockTaskModeTasks.get(0);
     }
 
-    private boolean isLockTaskModeViolationInternal(TaskRecord task, boolean isNewClearTask) {
+    private boolean isLockTaskModeViolationInternal(Task task, boolean isNewClearTask) {
         // TODO: Double check what's going on here. If the task is already in lock task mode, it's
         // likely whitelisted, so will return false below.
         if (isTaskLocked(task) && !isNewClearTask) {
@@ -339,7 +339,7 @@
                 & DevicePolicyManager.LOCK_TASK_FEATURE_KEYGUARD) != 0;
     }
 
-    private boolean isEmergencyCallTask(TaskRecord task) {
+    private boolean isEmergencyCallTask(Task task) {
         final Intent intent = task.intent;
         if (intent == null) {
             return false;
@@ -384,7 +384,7 @@
      * @throws SecurityException if the caller is not authorized to stop the lock task mode, i.e. if
      *                           they differ from the one that launched lock task mode.
      */
-    void stopLockTaskMode(@Nullable TaskRecord task, boolean isSystemCaller, int callingUid) {
+    void stopLockTaskMode(@Nullable Task task, boolean isSystemCaller, int callingUid) {
         if (mLockTaskModeState == LOCK_TASK_MODE_NONE) {
             return;
         }
@@ -407,8 +407,8 @@
             // It is possible lockTaskMode was started by the system process because
             // android:lockTaskMode is set to a locking value in the application manifest
             // instead of the app calling startLockTaskMode. In this case
-            // {@link TaskRecord.mLockTaskUid} will be 0, so we compare the callingUid to the
-            // {@link TaskRecord.effectiveUid} instead. Also caller with
+            // {@link Task.mLockTaskUid} will be 0, so we compare the callingUid to the
+            // {@link Task.effectiveUid} instead. Also caller with
             // {@link MANAGE_ACTIVITY_STACKS} can stop any lock task.
             if (callingUid != task.mLockTaskUid
                     && (task.mLockTaskUid != 0 || callingUid != task.effectiveUid)) {
@@ -425,7 +425,7 @@
      * Clear all locked tasks and request the end of LockTask mode.
      *
      * This method is called by UserController when starting a new foreground user, and,
-     * unlike {@link #stopLockTaskMode(TaskRecord, boolean, int)}, it doesn't perform the checks.
+     * unlike {@link #stopLockTaskMode(Task, boolean, int)}, it doesn't perform the checks.
      */
     void clearLockedTasks(String reason) {
         if (DEBUG_LOCKTASK) Slog.i(TAG_LOCKTASK, "clearLockedTasks: " + reason);
@@ -443,7 +443,7 @@
      *
      * @param task the task to be cleared from LockTask mode.
      */
-    void clearLockedTask(final TaskRecord task) {
+    void clearLockedTask(final Task task) {
         if (task == null || mLockTaskModeTasks.isEmpty()) return;
 
         if (task == mLockTaskModeTasks.get(0)) {
@@ -466,7 +466,7 @@
      * Remove the given task from the locked task list. If this was the last task in the list,
      * lock task mode is stopped.
      */
-    private void removeLockedTask(final TaskRecord task) {
+    private void removeLockedTask(final Task task) {
         if (!mLockTaskModeTasks.remove(task)) {
             return;
         }
@@ -527,7 +527,7 @@
      *                       at the calling task's mLockTaskAuth to decide which mode to start.
      * @param callingUid the caller that requested the launch of lock task mode.
      */
-    void startLockTaskMode(@NonNull TaskRecord task, boolean isSystemCaller, int callingUid) {
+    void startLockTaskMode(@NonNull Task task, boolean isSystemCaller, int callingUid) {
         if (!isSystemCaller) {
             task.mLockTaskUid = callingUid;
             if (task.mLockTaskAuth == LOCK_TASK_AUTH_PINNABLE) {
@@ -555,7 +555,7 @@
      * @param lockTaskModeState whether fully locked or pinned mode.
      * @param andResume whether the task should be brought to foreground as part of the operation.
      */
-    private void setLockTaskMode(@NonNull TaskRecord task, int lockTaskModeState,
+    private void setLockTaskMode(@NonNull Task task, int lockTaskModeState,
                                  String reason, boolean andResume) {
         // Should have already been checked, but do it again.
         if (task.mLockTaskAuth == LOCK_TASK_AUTH_DONT_LOCK) {
@@ -632,7 +632,7 @@
 
         boolean taskChanged = false;
         for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
+            final Task lockedTask = mLockTaskModeTasks.get(taskNdx);
             final boolean wasWhitelisted = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE
                     || lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED;
             lockedTask.setLockTaskAuth();
@@ -659,7 +659,7 @@
         }
 
         final ActivityRecord r = mSupervisor.mRootActivityContainer.topRunningActivity();
-        final TaskRecord task = (r != null) ? r.getTaskRecord() : null;
+        final Task task = (r != null) ? r.getTask() : null;
         if (mLockTaskModeTasks.isEmpty() && task!= null
                 && task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
             // This task must have just been authorized.
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 6cb1e76..a5b1fda 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -140,7 +140,7 @@
         public void startAnimation(Rect destinationBounds, Rect sourceRectHint,
                 int animationDuration) {
             synchronized (mService.mGlobalLock) {
-                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
+                final ActivityStack pinnedStack = mDisplayContent.getPinnedStack();
                 pinnedStack.animateResizePinnedStack(destinationBounds,
                         sourceRectHint, animationDuration, true /* fromFullscreen */);
             }
@@ -468,7 +468,7 @@
             }
             try {
                 final Rect animatingBounds = new Rect();
-                final TaskStack pinnedStack = mDisplayContent.getPinnedStack();
+                final ActivityStack pinnedStack = mDisplayContent.getPinnedStack();
                 if (pinnedStack != null) {
                     pinnedStack.getAnimationOrCurrentBounds(animatingBounds);
                 }
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 7169677..2f46937 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -119,7 +119,7 @@
     private static final long FREEZE_TASK_LIST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
 
     // Comparator to sort by taskId
-    private static final Comparator<TaskRecord> TASK_ID_COMPARATOR =
+    private static final Comparator<Task> TASK_ID_COMPARATOR =
             (lhs, rhs) -> rhs.mTaskId - lhs.mTaskId;
 
     // Placeholder variables to keep track of activities/apps that are no longer avialble while
@@ -135,12 +135,12 @@
         /**
          * Called when a task is added to the recent tasks list.
          */
-        void onRecentTaskAdded(TaskRecord task);
+        void onRecentTaskAdded(Task task);
 
         /**
          * Called when a task is removed from the recent tasks list.
          */
-        void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess);
+        void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess);
     }
 
     /**
@@ -171,7 +171,7 @@
             DEFAULT_INITIAL_CAPACITY);
 
     // List of all active recent tasks
-    private final ArrayList<TaskRecord> mTasks = new ArrayList<>();
+    private final ArrayList<Task> mTasks = new ArrayList<>();
     private final ArrayList<Callbacks> mCallbacks = new ArrayList<>();
 
     // These values are generally loaded from resources, but can be set dynamically in the tests
@@ -188,7 +188,7 @@
     private long mFreezeTaskListTimeoutMs = FREEZE_TASK_LIST_TIMEOUT_MS;
 
     // Mainly to avoid object recreation on multiple calls.
-    private final ArrayList<TaskRecord> mTmpRecents = new ArrayList<>();
+    private final ArrayList<Task> mTmpRecents = new ArrayList<>();
     private final HashMap<ComponentName, ActivityInfo> mTmpAvailActCache = new HashMap<>();
     private final HashMap<String, ApplicationInfo> mTmpAvailAppCache = new HashMap<>();
     private final SparseBooleanArray mTmpQuietProfileUserIds = new SparseBooleanArray();
@@ -211,7 +211,7 @@
                     final DisplayContent dc = rac.getActivityDisplay(displayId).mDisplayContent;
                     if (dc.pointWithinAppWindow(x, y)) {
                         final ActivityStack stack = mService.getTopDisplayFocusedStack();
-                        final TaskRecord topTask = stack != null ? stack.topTask() : null;
+                        final Task topTask = stack != null ? stack.topTask() : null;
                         resetFreezeTaskListReordering(topTask);
                     }
                 }
@@ -288,7 +288,7 @@
      * Commits the frozen recent task list order, moving the provided {@param topTask} to the
      * front of the list.
      */
-    void resetFreezeTaskListReordering(TaskRecord topTask) {
+    void resetFreezeTaskListReordering(Task topTask) {
         if (!mFreezeTaskListReordering) {
             return;
         }
@@ -319,9 +319,7 @@
     void resetFreezeTaskListReorderingOnTimeout() {
         synchronized (mService.mGlobalLock) {
             final ActivityStack focusedStack = mService.getTopDisplayFocusedStack();
-            final TaskRecord topTask = focusedStack != null
-                    ? focusedStack.topTask()
-                    : null;
+            final Task topTask = focusedStack != null ? focusedStack.topTask() : null;
             resetFreezeTaskListReordering(topTask);
         }
     }
@@ -432,14 +430,14 @@
         mCallbacks.remove(callback);
     }
 
-    private void notifyTaskAdded(TaskRecord task) {
+    private void notifyTaskAdded(Task task) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskAdded(task);
         }
         mTaskNotificationController.notifyTaskListUpdated();
     }
 
-    private void notifyTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+    private void notifyTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             mCallbacks.get(i).onRecentTaskRemoved(task, wasTrimmed, killProcess);
         }
@@ -463,14 +461,14 @@
 
         // Check if any tasks are added before recents is loaded
         final SparseBooleanArray preaddedTasks = new SparseBooleanArray();
-        for (final TaskRecord task : mTasks) {
+        for (final Task task : mTasks) {
             if (task.mUserId == userId && shouldPersistTaskLocked(task)) {
                 preaddedTasks.put(task.mTaskId, true);
             }
         }
 
         Slog.i(TAG, "Loading recents for user " + userId + " into memory.");
-        List<TaskRecord> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
+        List<Task> tasks = mTaskPersister.restoreTasksForUserLocked(userId, preaddedTasks);
         mTasks.addAll(tasks);
         cleanupLocked(userId);
         mUsersWithRecentsLoaded.put(userId, true);
@@ -509,7 +507,7 @@
     /**
      * Kicks off the task persister to write any pending tasks to disk.
      */
-    void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
+    void notifyTaskPersisterLocked(Task task, boolean flush) {
         final ActivityStack stack = task != null ? task.getStack() : null;
         if (stack != null && stack.isHomeOrRecentsStack()) {
             // Never persist the home or recents stack.
@@ -529,7 +527,7 @@
             }
         }
         for (int i = mTasks.size() - 1; i >= 0; i--) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             if (shouldPersistTaskLocked(task)) {
                 // Set of persisted taskIds for task.userId should not be null here
                 // TODO Investigate why it can happen. For now initialize with an empty set
@@ -543,7 +541,7 @@
         }
     }
 
-    private static boolean shouldPersistTaskLocked(TaskRecord task) {
+    private static boolean shouldPersistTaskLocked(Task task) {
         final ActivityStack stack = task.getStack();
         return task.isPersistable && (stack == null || !stack.isHomeOrRecentsStack());
     }
@@ -613,11 +611,11 @@
         }
 
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            TaskRecord tr = mTasks.get(i);
-            if (tr.mUserId == userId) {
+            Task task = mTasks.get(i);
+            if (task.mUserId == userId) {
                 if(DEBUG_TASKS) Slog.i(TAG_TASKS,
-                        "remove RecentTask " + tr + " when finishing user" + userId);
-                remove(tr);
+                        "remove RecentTask " + task + " when finishing user" + userId);
+                remove(task);
             }
         }
     }
@@ -625,17 +623,17 @@
     void onPackagesSuspendedChanged(String[] packages, boolean suspended, int userId) {
         final Set<String> packageNames = Sets.newHashSet(packages);
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            final TaskRecord tr = mTasks.get(i);
-            if (tr.realActivity != null
-                    && packageNames.contains(tr.realActivity.getPackageName())
-                    && tr.mUserId == userId
-                    && tr.realActivitySuspended != suspended) {
-               tr.realActivitySuspended = suspended;
+            final Task task = mTasks.get(i);
+            if (task.realActivity != null
+                    && packageNames.contains(task.realActivity.getPackageName())
+                    && task.mUserId == userId
+                    && task.realActivitySuspended != suspended) {
+               task.realActivitySuspended = suspended;
                if (suspended) {
-                   mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
+                   mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
                            REMOVE_FROM_RECENTS, "suspended-package");
                }
-               notifyTaskPersisterLocked(tr, false);
+               notifyTaskPersisterLocked(task, false);
             }
         }
     }
@@ -645,22 +643,22 @@
             return;
         }
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            final TaskRecord tr = mTasks.get(i);
-            if (tr.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(tr)) {
-                remove(tr);
+            final Task task = mTasks.get(i);
+            if (task.mUserId == userId && !mService.getLockTaskController().isTaskWhitelisted(task)) {
+                remove(task);
             }
         }
     }
 
     void removeTasksByPackageName(String packageName, int userId) {
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            final TaskRecord tr = mTasks.get(i);
+            final Task task = mTasks.get(i);
             final String taskPackageName =
-                    tr.getBaseIntent().getComponent().getPackageName();
-            if (tr.mUserId != userId) continue;
+                    task.getBaseIntent().getComponent().getPackageName();
+            if (task.mUserId != userId) continue;
             if (!taskPackageName.equals(packageName)) continue;
 
-            mSupervisor.removeTaskByIdLocked(tr.mTaskId, true, REMOVE_FROM_RECENTS,
+            mSupervisor.removeTaskByIdLocked(task.mTaskId, true, REMOVE_FROM_RECENTS,
                     "remove-package-task");
         }
     }
@@ -668,11 +666,11 @@
     void removeAllVisibleTasks(int userId) {
         Set<Integer> profileIds = getProfileIds(userId);
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            final TaskRecord tr = mTasks.get(i);
-            if (!profileIds.contains(tr.mUserId)) continue;
-            if (isVisibleRecentTask(tr)) {
+            final Task task = mTasks.get(i);
+            if (!profileIds.contains(task.mUserId)) continue;
+            if (isVisibleRecentTask(task)) {
                 mTasks.remove(i);
-                notifyTaskRemoved(tr, true /* wasTrimmed */, true /* killProcess */);
+                notifyTaskRemoved(task, true /* wasTrimmed */, true /* killProcess */);
             }
         }
     }
@@ -680,16 +678,16 @@
     void cleanupDisabledPackageTasksLocked(String packageName, Set<String> filterByClasses,
             int userId) {
         for (int i = mTasks.size() - 1; i >= 0; --i) {
-            final TaskRecord tr = mTasks.get(i);
-            if (userId != UserHandle.USER_ALL && tr.mUserId != userId) {
+            final Task task = mTasks.get(i);
+            if (userId != UserHandle.USER_ALL && task.mUserId != userId) {
                 continue;
             }
 
-            ComponentName cn = tr.intent != null ? tr.intent.getComponent() : null;
+            ComponentName cn = task.intent != null ? task.intent.getComponent() : null;
             final boolean sameComponent = cn != null && cn.getPackageName().equals(packageName)
                     && (filterByClasses == null || filterByClasses.contains(cn.getClassName()));
             if (sameComponent) {
-                mSupervisor.removeTaskByIdLocked(tr.mTaskId, false,
+                mSupervisor.removeTaskByIdLocked(task.mTaskId, false,
                         REMOVE_FROM_RECENTS, "disabled-package");
             }
         }
@@ -714,7 +712,7 @@
 
         final IPackageManager pm = AppGlobals.getPackageManager();
         for (int i = recentsCount - 1; i >= 0; i--) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             if (userId != UserHandle.USER_ALL && task.mUserId != userId) {
                 // Only look at tasks for the user ID of interest.
                 continue;
@@ -810,7 +808,7 @@
      * @return whether the given {@param task} can be added to the list without causing another
      * task to be trimmed as a result of that add.
      */
-    private boolean canAddTaskWithoutTrim(TaskRecord task) {
+    private boolean canAddTaskWithoutTrim(Task task) {
         return findRemoveIndexForAddTask(task) == -1;
     }
 
@@ -821,18 +819,18 @@
         final ArrayList<IBinder> list = new ArrayList<>();
         final int size = mTasks.size();
         for (int i = 0; i < size; i++) {
-            final TaskRecord tr = mTasks.get(i);
+            final Task task = mTasks.get(i);
             // Skip tasks that do not match the caller.  We don't need to verify
             // callingPackage, because we are also limiting to callingUid and know
             // that will limit to the correct security sandbox.
-            if (tr.effectiveUid != callingUid) {
+            if (task.effectiveUid != callingUid) {
                 continue;
             }
-            Intent intent = tr.getBaseIntent();
+            Intent intent = task.getBaseIntent();
             if (intent == null || !callingPackage.equals(intent.getComponent().getPackageName())) {
                 continue;
             }
-            AppTaskImpl taskImpl = new AppTaskImpl(mService, tr.mTaskId, callingUid);
+            AppTaskImpl taskImpl = new AppTaskImpl(mService, task.mTaskId, callingUid);
             list.add(taskImpl.asBinder());
         }
         return list;
@@ -893,11 +891,11 @@
         final int size = mTasks.size();
         int numVisibleTasks = 0;
         for (int i = 0; i < size; i++) {
-            final TaskRecord tr = mTasks.get(i);
+            final Task task = mTasks.get(i);
 
-            if (isVisibleRecentTask(tr)) {
+            if (isVisibleRecentTask(task)) {
                 numVisibleTasks++;
-                if (isInVisibleRange(tr, i, numVisibleTasks, withExcluded)) {
+                if (isInVisibleRange(task, i, numVisibleTasks, withExcluded)) {
                     // Fall through
                 } else {
                     // Not in visible range
@@ -914,48 +912,48 @@
             }
 
             // Only add calling user or related users recent tasks
-            if (!includedUsers.contains(Integer.valueOf(tr.mUserId))) {
-                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + tr);
+            if (!includedUsers.contains(Integer.valueOf(task.mUserId))) {
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not user: " + task);
                 continue;
             }
 
-            if (tr.realActivitySuspended) {
-                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + tr);
+            if (task.realActivitySuspended) {
+                if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, activity suspended: " + task);
                 continue;
             }
 
             if (!getTasksAllowed) {
                 // If the caller doesn't have the GET_TASKS permission, then only
                 // allow them to see a small subset of tasks -- their own and home.
-                if (!tr.isActivityTypeHome() && tr.effectiveUid != callingUid) {
-                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + tr);
+                if (!task.isActivityTypeHome() && task.effectiveUid != callingUid) {
+                    if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Skipping, not allowed: " + task);
                     continue;
                 }
             }
 
-            if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
+            if (task.autoRemoveRecents && task.getTopActivity() == null) {
                 // Don't include auto remove tasks that are finished or finishing.
                 if (DEBUG_RECENTS) {
-                    Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + tr);
+                    Slog.d(TAG_RECENTS, "Skipping, auto-remove without activity: " + task);
                 }
                 continue;
             }
-            if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !tr.isAvailable) {
+            if ((flags & RECENT_IGNORE_UNAVAILABLE) != 0 && !task.isAvailable) {
                 if (DEBUG_RECENTS) {
-                    Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + tr);
+                    Slog.d(TAG_RECENTS, "Skipping, unavail real act: " + task);
                 }
                 continue;
             }
 
-            if (!tr.mUserSetupComplete) {
+            if (!task.mUserSetupComplete) {
                 // Don't include task launched while user is not done setting-up.
                 if (DEBUG_RECENTS) {
-                    Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + tr);
+                    Slog.d(TAG_RECENTS, "Skipping, user setup not complete: " + task);
                 }
                 continue;
             }
 
-            final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(tr);
+            final ActivityManager.RecentTaskInfo rti = createRecentTaskInfo(task);
             if (!getDetailedTasks) {
                 rti.baseIntent.replaceExtras((Bundle) null);
             }
@@ -971,7 +969,7 @@
     void getPersistableTaskIds(ArraySet<Integer> persistentTaskIds) {
         final int size = mTasks.size();
         for (int i = 0; i < size; i++) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             if (TaskPersister.DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task
                     + " persistable=" + task.isPersistable);
             final ActivityStack stack = task.getStack();
@@ -987,7 +985,7 @@
     }
 
     @VisibleForTesting
-    ArrayList<TaskRecord> getRawTasks() {
+    ArrayList<Task> getRawTasks() {
         return mTasks;
     }
 
@@ -999,11 +997,11 @@
         final int size = mTasks.size();
         int numVisibleTasks = 0;
         for (int i = 0; i < size; i++) {
-            final TaskRecord tr = mTasks.get(i);
-            if (isVisibleRecentTask(tr)) {
+            final Task task = mTasks.get(i);
+            if (isVisibleRecentTask(task)) {
                 numVisibleTasks++;
-                if (isInVisibleRange(tr, i, numVisibleTasks, false /* skipExcludedCheck */)) {
-                    res.put(tr.mTaskId, true);
+                if (isInVisibleRange(task, i, numVisibleTasks, false /* skipExcludedCheck */)) {
+                    res.put(task.mTaskId, true);
                 }
             }
         }
@@ -1013,12 +1011,12 @@
     /**
      * @return the task in the task list with the given {@param id} if one exists.
      */
-    TaskRecord getTask(int id) {
+    Task getTask(int id) {
         final int recentsCount = mTasks.size();
         for (int i = 0; i < recentsCount; i++) {
-            TaskRecord tr = mTasks.get(i);
-            if (tr.mTaskId == id) {
-                return tr;
+            Task task = mTasks.get(i);
+            if (task.mTaskId == id) {
+                return task;
             }
         }
         return null;
@@ -1027,7 +1025,7 @@
     /**
      * Add a new task to the recent tasks list.
      */
-    void add(TaskRecord task) {
+    void add(Task task) {
         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);
 
         final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
@@ -1098,7 +1096,7 @@
         } else if (isAffiliated) {
             // If this is a new affiliated task, then move all of the affiliated tasks
             // to the front and insert this new one.
-            TaskRecord other = task.mNextAffiliate;
+            Task other = task.mNextAffiliate;
             if (other == null) {
                 other = task.mPrevAffiliate;
             }
@@ -1154,7 +1152,7 @@
     /**
      * Add the task to the bottom if possible.
      */
-    boolean addToBottom(TaskRecord task) {
+    boolean addToBottom(Task task) {
         if (!canAddTaskWithoutTrim(task)) {
             // Adding this task would cause the task to be removed (since it's appended at
             // the bottom and would be trimmed) so just return now
@@ -1168,7 +1166,7 @@
     /**
      * Remove a task from the recent tasks list.
      */
-    void remove(TaskRecord task) {
+    void remove(Task task) {
         mTasks.remove(task);
         notifyTaskRemoved(task, false /* wasTrimmed */, false /* killProcess */);
     }
@@ -1186,10 +1184,10 @@
 
         // Remove from the end of the list until we reach the max number of recents
         while (recentsCount > mGlobalMaxNumTasks) {
-            final TaskRecord tr = mTasks.remove(recentsCount - 1);
-            notifyTaskRemoved(tr, true /* wasTrimmed */, false /* killProcess */);
+            final Task task = mTasks.remove(recentsCount - 1);
+            notifyTaskRemoved(task, true /* wasTrimmed */, false /* killProcess */);
             recentsCount--;
-            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + tr
+            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming over max-recents task=" + task
                     + " max=" + mGlobalMaxNumTasks);
         }
 
@@ -1208,7 +1206,7 @@
         // Remove any inactive tasks, calculate the latest set of visible tasks.
         int numVisibleTasks = 0;
         for (int i = 0; i < mTasks.size();) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
 
             if (isActiveRecentTask(task, mTmpQuietProfileUserIds)) {
                 if (!mHasVisibleRecentTasks) {
@@ -1250,7 +1248,7 @@
     /**
      * @return whether the given task should be considered active.
      */
-    private boolean isActiveRecentTask(TaskRecord task, SparseBooleanArray quietProfileUserIds) {
+    private boolean isActiveRecentTask(Task task, SparseBooleanArray quietProfileUserIds) {
         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isActiveRecentTask: task=" + task
                 + " globalMax=" + mGlobalMaxNumTasks);
 
@@ -1262,7 +1260,7 @@
 
         if (task.mAffiliatedTaskId != INVALID_TASK_ID && task.mAffiliatedTaskId != task.mTaskId) {
             // Keep the task active if its affiliated task is also active
-            final TaskRecord affiliatedTask = getTask(task.mAffiliatedTaskId);
+            final Task affiliatedTask = getTask(task.mAffiliatedTaskId);
             if (affiliatedTask != null) {
                 if (!isActiveRecentTask(affiliatedTask, quietProfileUserIds)) {
                     if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG,
@@ -1280,7 +1278,7 @@
      * @return whether the given active task should be presented to the user through SystemUI.
      */
     @VisibleForTesting
-    boolean isVisibleRecentTask(TaskRecord task) {
+    boolean isVisibleRecentTask(Task task) {
         if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "isVisibleRecentTask: task=" + task
                 + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
                 + " sessionDuration=" + mActiveTasksSessionDurationMs
@@ -1338,7 +1336,7 @@
     /**
      * @return whether the given visible task is within the policy range.
      */
-    private boolean isInVisibleRange(TaskRecord task, int taskIndex, int numVisibleTasks,
+    private boolean isInVisibleRange(Task task, int taskIndex, int numVisibleTasks,
             boolean skipExcludedCheck) {
         if (!skipExcludedCheck) {
             // Keep the most recent task even if it is excluded from recents
@@ -1376,7 +1374,7 @@
     /**
      * @return whether the given task can be trimmed even if it is outside the visible range.
      */
-    protected boolean isTrimmable(TaskRecord task) {
+    protected boolean isTrimmable(Task task) {
         final ActivityStack stack = task.getStack();
 
         // No stack for task, just trim it
@@ -1399,7 +1397,7 @@
      * If needed, remove oldest existing entries in recents that are for the same kind
      * of task as the given one.
      */
-    private void removeForAddTask(TaskRecord task) {
+    private void removeForAddTask(Task task) {
         final int removeIndex = findRemoveIndexForAddTask(task);
         if (removeIndex == -1) {
             // Nothing to trim
@@ -1409,7 +1407,7 @@
         // There is a similar task that will be removed for the addition of {@param task}, but it
         // can be the same task, and if so, the task will be re-added in add(), so skip the
         // callbacks here.
-        final TaskRecord removedTask = mTasks.remove(removeIndex);
+        final Task removedTask = mTasks.remove(removeIndex);
         if (removedTask != task) {
             notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
             if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
@@ -1422,7 +1420,7 @@
      * Find the task that would be removed if the given {@param task} is added to the recent tasks
      * list (if any).
      */
-    private int findRemoveIndexForAddTask(TaskRecord task) {
+    private int findRemoveIndexForAddTask(Task task) {
         if (mFreezeTaskListReordering) {
             // Defer removing tasks due to the addition of new tasks until the task list is unfrozen
             return -1;
@@ -1433,15 +1431,15 @@
         final boolean document = intent != null && intent.isDocument();
         int maxRecents = task.maxRecents - 1;
         for (int i = 0; i < recentsCount; i++) {
-            final TaskRecord tr = mTasks.get(i);
-            if (task != tr) {
-                if (!hasCompatibleActivityTypeAndWindowingMode(task, tr)
-                        || task.mUserId != tr.mUserId) {
+            final Task t = mTasks.get(i);
+            if (task != t) {
+                if (!hasCompatibleActivityTypeAndWindowingMode(task, t)
+                        || task.mUserId != t.mUserId) {
                     continue;
                 }
-                final Intent trIntent = tr.intent;
+                final Intent trIntent = t.intent;
                 final boolean sameAffinity =
-                        task.affinity != null && task.affinity.equals(tr.affinity);
+                        task.affinity != null && task.affinity.equals(t.affinity);
                 final boolean sameIntent = intent != null && intent.filterEquals(trIntent);
                 boolean multiTasksAllowed = false;
                 final int flags = intent.getFlags();
@@ -1458,8 +1456,8 @@
                 if (bothDocuments) {
                     // Do these documents belong to the same activity?
                     final boolean sameActivity = task.realActivity != null
-                            && tr.realActivity != null
-                            && task.realActivity.equals(tr.realActivity);
+                            && t.realActivity != null
+                            && task.realActivity.equals(t.realActivity);
                     if (!sameActivity) {
                         // If the document is open in another app or is not the same document, we
                         // don't need to trim it.
@@ -1487,7 +1485,7 @@
 
     // Extract the affiliates of the chain containing recent at index start.
     private int processNextAffiliateChainLocked(int start) {
-        final TaskRecord startTask = mTasks.get(start);
+        final Task startTask = mTasks.get(start);
         final int affiliateId = startTask.mAffiliatedTaskId;
 
         // Quick identification of isolated tasks. I.e. those not launched behind.
@@ -1503,7 +1501,7 @@
         // Remove all tasks that are affiliated to affiliateId and put them in mTmpRecents.
         mTmpRecents.clear();
         for (int i = mTasks.size() - 1; i >= start; --i) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             if (task.mAffiliatedTaskId == affiliateId) {
                 mTasks.remove(i);
                 mTmpRecents.add(task);
@@ -1516,7 +1514,7 @@
 
         // Go through and fix up the linked list.
         // The first one is the end of the chain and has no next.
-        final TaskRecord first = mTmpRecents.get(0);
+        final Task first = mTmpRecents.get(0);
         first.inRecents = true;
         if (first.mNextAffiliate != null) {
             Slog.w(TAG, "Link error 1 first.next=" + first.mNextAffiliate);
@@ -1526,8 +1524,8 @@
         // Everything in the middle is doubly linked from next to prev.
         final int tmpSize = mTmpRecents.size();
         for (int i = 0; i < tmpSize - 1; ++i) {
-            final TaskRecord next = mTmpRecents.get(i);
-            final TaskRecord prev = mTmpRecents.get(i + 1);
+            final Task next = mTmpRecents.get(i);
+            final Task prev = mTmpRecents.get(i + 1);
             if (next.mPrevAffiliate != prev) {
                 Slog.w(TAG, "Link error 2 next=" + next + " prev=" + next.mPrevAffiliate +
                         " setting prev=" + prev);
@@ -1543,7 +1541,7 @@
             prev.inRecents = true;
         }
         // The last one is the beginning of the list and has no prev.
-        final TaskRecord last = mTmpRecents.get(tmpSize - 1);
+        final Task last = mTmpRecents.get(tmpSize - 1);
         if (last.mPrevAffiliate != null) {
             Slog.w(TAG, "Link error 4 last.prev=" + last.mPrevAffiliate);
             last.setPrevAffiliate(null);
@@ -1558,9 +1556,9 @@
         return start + tmpSize;
     }
 
-    private boolean moveAffiliatedTasksToFront(TaskRecord task, int taskIndex) {
+    private boolean moveAffiliatedTasksToFront(Task task, int taskIndex) {
         int recentsCount = mTasks.size();
-        TaskRecord top = task;
+        Task top = task;
         int topIndex = taskIndex;
         while (top.mNextAffiliate != null && topIndex > 0) {
             top = top.mNextAffiliate;
@@ -1571,9 +1569,9 @@
         // Find the end of the chain, doing a sanity check along the way.
         boolean sane = top.mAffiliatedTaskId == task.mAffiliatedTaskId;
         int endIndex = topIndex;
-        TaskRecord prev = top;
+        Task prev = top;
         while (endIndex < recentsCount) {
-            TaskRecord cur = mTasks.get(endIndex);
+            Task cur = mTasks.get(endIndex);
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: looking at next chain @"
                     + endIndex + " " + cur);
             if (cur == top) {
@@ -1648,7 +1646,7 @@
             for (int i=topIndex; i<=endIndex; i++) {
                 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: moving affiliated " + task
                         + " from " + i + " to " + (i-topIndex));
-                TaskRecord cur = mTasks.remove(i);
+                Task cur = mTasks.remove(i);
                 mTasks.add(i - topIndex, cur);
             }
             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "addRecent: done moving tasks  " +  topIndex
@@ -1676,9 +1674,9 @@
         boolean printedHeader = false;
         final int size = mTasks.size();
         for (int i = 0; i < size; i++) {
-            final TaskRecord tr = mTasks.get(i);
-            if (dumpPackage != null && (tr.realActivity == null ||
-                    !dumpPackage.equals(tr.realActivity.getPackageName()))) {
+            final Task task = mTasks.get(i);
+            if (dumpPackage != null && (task.realActivity == null ||
+                    !dumpPackage.equals(task.realActivity.getPackageName()))) {
                 continue;
             }
 
@@ -1688,9 +1686,9 @@
                 printedAnything = true;
             }
             pw.print("  * Recent #"); pw.print(i); pw.print(": ");
-            pw.println(tr);
+            pw.println(task);
             if (dumpAll) {
-                tr.dump(pw, "    ");
+                task.dump(pw, "    ");
             }
         }
 
@@ -1724,9 +1722,9 @@
     }
 
     /**
-     * Creates a new RecentTaskInfo from a TaskRecord.
+     * Creates a new RecentTaskInfo from a Task.
      */
-    ActivityManager.RecentTaskInfo createRecentTaskInfo(TaskRecord tr) {
+    ActivityManager.RecentTaskInfo createRecentTaskInfo(Task tr) {
         ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
         tr.fillTaskInfo(rti);
         // Fill in some deprecated values
@@ -1740,7 +1738,7 @@
      *         compatible. This is necessary because we currently don't persist the activity type
      *         or the windowing mode with the task, so they can be undefined when restored.
      */
-    private boolean hasCompatibleActivityTypeAndWindowingMode(TaskRecord t1, TaskRecord t2) {
+    private boolean hasCompatibleActivityTypeAndWindowingMode(Task t1, Task t2) {
         final int activityType = t1.getActivityType();
         final int windowingMode = t1.getWindowingMode();
         final boolean isUndefinedType = activityType == ACTIVITY_TYPE_UNDEFINED;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 01cbc5d..caf95de 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -211,9 +211,9 @@
                 // If there are multiple tasks in the target stack (ie. the home stack, with 3p
                 // and default launchers coexisting), then move the task to the top as a part of
                 // moving the stack to the front
-                final TaskRecord task = targetActivity.getTaskRecord();
+                final Task task = targetActivity.getTask();
                 if (targetStack.topTask() != task) {
-                    targetStack.insertTaskAtTop(task, targetActivity);
+                    targetStack.positionChildAtTop(task);
                 }
             } else {
                 // No recents activity, create the new recents activity bottom most
@@ -328,7 +328,7 @@
                         if (sendUserLeaveHint) {
                             // Setting this allows the previous app to PiP.
                             mStackSupervisor.mUserLeaving = true;
-                            targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
+                            targetStack.moveTaskToFrontLocked(targetActivity.getTask(),
                                     true /* noAnimation */, null /* activityOptions */,
                                     targetActivity.appTimeTracker,
                                     "RecentsAnimation.onAnimationFinished()");
@@ -428,7 +428,7 @@
         // cases:
         // 1) The next launching task is not being animated by the recents animation
         // 2) The next task is home activity. (i.e. pressing home key to back home in recents).
-        if ((!controller.isAnimatingTask(stack.getTaskStack().getTopChild())
+        if ((!controller.isAnimatingTask(stack.getTopChild())
                 || controller.isTargetApp(stack.getTopActivity()))
                 && controller.shouldDeferCancelUntilNextTransition()) {
             // Always prepare an app transition since we rely on the transition callbacks to cleanup
@@ -491,7 +491,7 @@
         }
 
         for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
-            final TaskRecord task = targetStack.getChildAt(i);
+            final Task task = targetStack.getChildAt(i);
             if (task.mUserId == mUserId
                     && task.getBaseIntent().getComponent().equals(mTargetIntent.getComponent())) {
                 return task.getTopActivity();
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 7a3e43b..282144e 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -366,7 +366,7 @@
         // Make leashes for each of the visible/target tasks and add it to the recents animation to
         // be started
         final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
-        final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
+        final ActivityStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
                 targetActivityType);
         if (targetStack != null) {
             for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
@@ -410,7 +410,8 @@
         }
 
         // Save the minimized home height
-        final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
+        final ActivityStack dockedStack =
+                mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
         mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
                 mDisplayContent.getConfiguration(),
                 dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
diff --git a/services/core/java/com/android/server/wm/RootActivityContainer.java b/services/core/java/com/android/server/wm/RootActivityContainer.java
index 3eef749..5a21016 100644
--- a/services/core/java/com/android/server/wm/RootActivityContainer.java
+++ b/services/core/java/com/android/server/wm/RootActivityContainer.java
@@ -62,8 +62,8 @@
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
-import static com.android.server.wm.TaskRecord.REPARENT_LEAVE_STACK_IN_PLACE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
 
 import static java.lang.Integer.MAX_VALUE;
 
@@ -857,10 +857,10 @@
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getChildAt(stackNdx);
-                stack.switchUserLocked(userId);
-                TaskRecord task = stack.topTask();
+                stack.switchUser(userId);
+                Task task = stack.topTask();
                 if (task != null) {
-                    stack.positionChildWindowContainerAtTop(task);
+                    stack.positionChildAtTop(task);
                 }
             }
         }
@@ -930,7 +930,7 @@
             return;
         }
 
-        stack.reparent(activityDisplay, onTop, false /* displayRemoved */);
+        stack.reparent(activityDisplay.mDisplayContent, onTop);
         // TODO(multi-display): resize stacks properly if moved from split-screen.
     }
 
@@ -966,7 +966,7 @@
         final ActivityDisplay display = r.getActivityStack().getDisplay();
 
         try {
-            final TaskRecord task = r.getTaskRecord();
+            final Task task = r.getTask();
 
             final ActivityStack pinnedStack = display.getPinnedStack();
             // This will change the pinned stack's windowing mode to its original mode, ensuring
@@ -995,7 +995,7 @@
                 // activity into that task, and then reparent the whole task to the new stack. This
                 // ensures that all the necessary work to migrate states in the old and new stacks
                 // is also done.
-                final TaskRecord newTask = task.getStack().createTaskRecord(
+                final Task newTask = task.getStack().createTask(
                         mStackSupervisor.getNextTaskIdForUserLocked(r.mUserId), r.info,
                         r.intent, null, null, true);
                 r.reparent(newTask, MAX_VALUE, "moveActivityToStack");
@@ -1090,7 +1090,7 @@
      * @return The task id that was finished in this stack, or INVALID_TASK_ID if none was finished.
      */
     int finishTopCrashedActivities(WindowProcessController app, String reason) {
-        TaskRecord finishedTask = null;
+        Task finishedTask = null;
         ActivityStack focusedStack = getTopDisplayFocusedStack();
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
@@ -1098,7 +1098,7 @@
             // so we need to be careful with indexes in the loop and check child count every time.
             for (int stackNdx = 0; stackNdx < display.getChildCount(); ++stackNdx) {
                 final ActivityStack stack = display.getChildAt(stackNdx);
-                final TaskRecord t = stack.finishTopCrashedActivityLocked(app, reason);
+                final Task t = stack.finishTopCrashedActivityLocked(app, reason);
                 if (stack == focusedStack || finishedTask == null) {
                     finishedTask = t;
                 }
@@ -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);
                 }
             }
         }
@@ -1244,7 +1247,7 @@
         final int displayId = stack.mDisplayId;
         final ActivityDisplay display = getActivityDisplay(displayId);
         ActivityManager.StackInfo info = new ActivityManager.StackInfo();
-        stack.getWindowContainerBounds(info.bounds);
+        stack.getBounds(info.bounds);
         info.displayId = displayId;
         info.stackId = stack.mStackId;
         info.userId = stack.mCurrentUser;
@@ -1253,14 +1256,14 @@
         info.position = display != null ? display.getIndexOf(stack) : 0;
         info.configuration.setTo(stack.getConfiguration());
 
-        ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        ArrayList<Task> tasks = stack.getAllTasks();
         final int numTasks = tasks.size();
         int[] taskIds = new int[numTasks];
         String[] taskNames = new String[numTasks];
         Rect[] taskBounds = new Rect[numTasks];
         int[] taskUserIds = new int[numTasks];
         for (int i = 0; i < numTasks; ++i) {
-            final TaskRecord task = tasks.get(i);
+            final Task task = tasks.get(i);
             taskIds[i] = task.mTaskId;
             taskNames[i] = task.origActivity != null ? task.origActivity.flattenToString()
                     : task.realActivity != null ? task.realActivity.flattenToString()
@@ -1547,7 +1550,7 @@
 
     void releaseSomeActivitiesLocked(WindowProcessController app, String reason) {
         // Tasks is non-null only if two or more tasks are found.
-        ArraySet<TaskRecord> tasks = app.getReleaseSomeActivitiesTasks();
+        ArraySet<Task> tasks = app.getReleaseSomeActivitiesTasks();
         if (tasks == null) {
             if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Didn't find two or more tasks to release");
             return;
@@ -1630,7 +1633,7 @@
     }
 
     ActivityStack getLaunchStack(@Nullable ActivityRecord r,
-            @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop) {
+            @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop) {
         return getLaunchStack(r, options, candidateTask, onTop, null /* launchParams */,
                 -1 /* no realCallingPid */, -1 /* no realCallingUid */);
     }
@@ -1648,7 +1651,7 @@
      * @return The stack to use for the launch or INVALID_STACK_ID.
      */
     ActivityStack getLaunchStack(@Nullable ActivityRecord r,
-            @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, boolean onTop,
+            @Nullable ActivityOptions options, @Nullable Task candidateTask, boolean onTop,
             @Nullable LaunchParamsController.LaunchParams launchParams, int realCallingPid,
             int realCallingUid) {
         int taskId = INVALID_TASK_ID;
@@ -1666,7 +1669,7 @@
         if (taskId != INVALID_TASK_ID) {
             // Temporarily set the task id to invalid in case in re-entry.
             options.setLaunchTaskId(INVALID_TASK_ID);
-            final TaskRecord task = anyTaskForId(taskId,
+            final Task task = anyTaskForId(taskId,
                     MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, options, onTop);
             options.setLaunchTaskId(taskId);
             if (task != null) {
@@ -1765,7 +1768,7 @@
      * @return Existing stack if there is a valid one, new dynamic stack if it is valid or null.
      */
     private ActivityStack getValidLaunchStackOnDisplay(int displayId, @NonNull ActivityRecord r,
-            @Nullable TaskRecord candidateTask, @Nullable ActivityOptions options,
+            @Nullable Task candidateTask, @Nullable ActivityOptions options,
             @Nullable LaunchParamsController.LaunchParams launchParams) {
         final ActivityDisplay activityDisplay = getActivityDisplayOrCreate(displayId);
         if (activityDisplay == null) {
@@ -1780,8 +1783,7 @@
         // If {@code r} is already in target display and its task is the same as the candidate task,
         // the intention should be getting a launch stack for the reusable activity, so we can use
         // the existing stack.
-        if (candidateTask != null
-                && (r.getTaskRecord() == null || r.getTaskRecord() == candidateTask)) {
+        if (candidateTask != null && (r.getTask() == null || r.getTask() == candidateTask)) {
             final int attachedDisplayId = r.getDisplayId();
             if (attachedDisplayId == INVALID_DISPLAY || attachedDisplayId == displayId) {
                 return candidateTask.getStack();
@@ -1846,7 +1848,7 @@
     }
 
     int resolveActivityType(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
-            @Nullable TaskRecord task) {
+            @Nullable Task task) {
         // Preference is given to the activity type for the activity then the task since the type
         // once set shouldn't change.
         int activityType = r != null ? r.getActivityType() : ACTIVITY_TYPE_UNDEFINED;
@@ -2103,9 +2105,9 @@
                 final ActivityDisplay display = mActivityDisplays.get(displayNdx);
                 for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                     final ActivityStack stack = display.getChildAt(stackNdx);
-                    final List<TaskRecord> tasks = stack.getAllTasks();
+                    final List<Task> tasks = stack.getAllTasks();
                     for (int taskNdx = tasks.size() - 1; taskNdx >= 0; taskNdx--) {
-                        final TaskRecord task = tasks.get(taskNdx);
+                        final Task task = tasks.get(taskNdx);
 
                         // Check the task for a top activity belonging to userId, or returning a
                         // result to an activity belonging to userId. Example case: a document
@@ -2133,7 +2135,7 @@
      *
      * @return {@code true} if the top activity looks like it belongs to {@param userId}.
      */
-    private boolean taskTopActivityIsUser(TaskRecord task, @UserIdInt int userId) {
+    private boolean taskTopActivityIsUser(Task task, @UserIdInt int userId) {
         // To handle the case that work app is in the task but just is not the top one.
         final ActivityRecord activityRecord = task.getTopActivity();
         final ActivityRecord resultTo = (activityRecord != null ? activityRecord.resultTo : null);
@@ -2152,22 +2154,22 @@
         }
     }
 
-    TaskRecord anyTaskForId(int id) {
+    Task anyTaskForId(int id) {
         return anyTaskForId(id, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE);
     }
 
-    TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
+    Task anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode) {
         return anyTaskForId(id, matchMode, null, !ON_TOP);
     }
 
     /**
-     * Returns a {@link TaskRecord} for the input id if available. {@code null} otherwise.
+     * Returns a {@link Task} for the input id if available. {@code null} otherwise.
      * @param id Id of the task we would like returned.
      * @param matchMode The mode to match the given task id in.
      * @param aOptions The activity options to use for restoration. Can be null.
      * @param onTop If the stack for the task should be the topmost on the display.
      */
-    TaskRecord anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode,
+    Task anyTaskForId(int id, @AnyTaskForIdMatchTaskMode int matchMode,
             @Nullable ActivityOptions aOptions, boolean onTop) {
         // If options are set, ensure that we are attempting to actually restore a task
         if (matchMode != MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE && aOptions != null) {
@@ -2180,7 +2182,7 @@
             final ActivityDisplay display = mActivityDisplays.get(displayNdx);
             for (int stackNdx = display.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = display.getChildAt(stackNdx);
-                final TaskRecord task = stack.taskForIdLocked(id);
+                final Task task = stack.taskForIdLocked(id);
                 if (task == null) {
                     continue;
                 }
@@ -2208,7 +2210,7 @@
         // Otherwise, check the recent tasks and return if we find it there and we are not restoring
         // the task from recents
         if (DEBUG_RECENTS) Slog.v(TAG_RECENTS, "Looking for task id=" + id + " in recents");
-        final TaskRecord task = mStackSupervisor.mRecentTasks.getTask(id);
+        final Task task = mStackSupervisor.mRecentTasks.getTask(id);
 
         if (task == null) {
             if (DEBUG_RECENTS) {
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 149bcfb..565f95e 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -412,10 +412,10 @@
         }
     }
 
-    TaskStack getStack(int windowingMode, int activityType) {
+    ActivityStack getStack(int windowingMode, int activityType) {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final DisplayContent dc = mChildren.get(i);
-            final TaskStack stack = dc.getStack(windowingMode, activityType);
+            final ActivityStack stack = dc.getStack(windowingMode, activityType);
             if (stack != null) {
                 return stack;
             }
@@ -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/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 81a8547..f2678bb 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -33,11 +33,11 @@
 class RunningTasks {
 
     // Comparator to sort by last active time (descending)
-    private static final Comparator<TaskRecord> LAST_ACTIVE_TIME_COMPARATOR =
+    private static final Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR =
             (o1, o2) -> Long.signum(o2.lastActiveTime - o1.lastActiveTime);
 
-    private final TreeSet<TaskRecord> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
-    private final ArrayList<TaskRecord> mTmpStackTasks = new ArrayList<>();
+    private final TreeSet<Task> mTmpSortedSet = new TreeSet<>(LAST_ACTIVE_TIME_COMPARATOR);
+    private final ArrayList<Task> mTmpStackTasks = new ArrayList<>();
 
     void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
             @WindowingMode int ignoreWindowingMode, ArrayList<ActivityDisplay> activityDisplays,
@@ -62,13 +62,13 @@
         }
 
         // Take the first {@param maxNum} tasks and create running task infos for them
-        final Iterator<TaskRecord> iter = mTmpSortedSet.iterator();
+        final Iterator<Task> iter = mTmpSortedSet.iterator();
         while (iter.hasNext()) {
             if (maxNum == 0) {
                 break;
             }
 
-            final TaskRecord task = iter.next();
+            final Task task = iter.next();
             list.add(createRunningTaskInfo(task));
             maxNum--;
         }
@@ -77,7 +77,7 @@
     /**
      * Constructs a {@link RunningTaskInfo} from a given {@param task}.
      */
-    private RunningTaskInfo createRunningTaskInfo(TaskRecord task) {
+    private RunningTaskInfo createRunningTaskInfo(Task task) {
         final RunningTaskInfo rti = new RunningTaskInfo();
         task.fillTaskInfo(rti);
         // Fill in some deprecated values
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 157bd3b..c19c96f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
 import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
@@ -558,8 +559,6 @@
         private SurfaceAnimator mEnterBlackFrameAnimator;
         private SurfaceAnimator mScreenshotRotationAnimator;
         private SurfaceAnimator mRotateScreenAnimator;
-        private final Runnable mNoopCallback = () -> { // b/141177184
-        };
 
         /**
          * Start the rotation animation of the display and the screenshot on the
@@ -592,7 +591,7 @@
                             .setHeight(mDisplayContent.getSurfaceHeight())
                             .build(),
                     createWindowAnimationSpec(mRotateEnterAnimation),
-                    this::cancel);
+                    this::onAnimationEnd);
         }
 
         private SurfaceAnimator startScreenshotAlphaAnimation() {
@@ -603,7 +602,7 @@
                             .setHeight(mHeight)
                             .build(),
                     createWindowAnimationSpec(mRotateAlphaAnimation),
-                    mNoopCallback);
+                    this::onAnimationEnd);
         }
 
         private SurfaceAnimator startEnterBlackFrameAnimation() {
@@ -612,7 +611,7 @@
                             .setAnimationLeashParent(mDisplayContent.getOverlayLayer())
                             .build(),
                     createWindowAnimationSpec(mRotateEnterAnimation),
-                    mNoopCallback);
+                    this::onAnimationEnd);
         }
 
         private SurfaceAnimator startScreenshotRotationAnimation() {
@@ -654,18 +653,38 @@
         }
 
         private void onAnimationEnd() {
-            mEnterBlackFrameAnimator = null;
-            mScreenshotRotationAnimator = null;
-            mRotateScreenAnimator = null;
-            mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
-            kill();
-            mService.updateRotation(false, false);
-            AccessibilityController accessibilityController = mService.mAccessibilityController;
+            synchronized (mService.mGlobalLock) {
+                if (isAnimating()) {
+                    ProtoLog.v(WM_DEBUG_ORIENTATION,
+                            "ScreenRotation sill animating: mDisplayAnimator: %s\n"
+                                    + "mEnterBlackFrameAnimator: "
+                                    + "%s\nmRotateScreenAnimator: %s\n"
+                                    + "mScreenshotRotationAnimator: %s",
+                            mDisplayAnimator != null
+                                    ? mDisplayAnimator.isAnimating() : null,
+                            mEnterBlackFrameAnimator != null
+                                    ? mEnterBlackFrameAnimator.isAnimating() : null,
+                            mRotateScreenAnimator != null
+                                    ? mRotateScreenAnimator.isAnimating() : null,
+                            mScreenshotRotationAnimator != null
+                                    ? mScreenshotRotationAnimator.isAnimating() : null
+                    );
+                    return;
+                }
+                ProtoLog.d(WM_DEBUG_ORIENTATION, "ScreenRotationAnimation onAnimationEnd");
+                mEnterBlackFrameAnimator = null;
+                mScreenshotRotationAnimator = null;
+                mRotateScreenAnimator = null;
+                mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
+                kill();
+                mService.updateRotation(false, false);
+                AccessibilityController accessibilityController = mService.mAccessibilityController;
 
-            if (accessibilityController != null) {
-                // We just finished rotation animation which means we did not
-                // announce the rotation and waited for it to end, announce now.
-                accessibilityController.onRotationChangedLocked(mDisplayContent);
+                if (accessibilityController != null) {
+                    // We just finished rotation animation which means we did not
+                    // announce the rotation and waited for it to end, announce now.
+                    accessibilityController.onRotationChangedLocked(mDisplayContent);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 96be7cc..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 "
@@ -263,11 +263,9 @@
     @Override
     public IBinder performDrag(IWindow window, int flags, SurfaceControl surface, int touchSource,
             float touchX, float touchY, float thumbCenterX, float thumbCenterY, ClipData data) {
-        final int callerPid = Binder.getCallingPid();
-        final int callerUid = Binder.getCallingUid();
         final long ident = Binder.clearCallingIdentity();
         try {
-            return mDragDropController.performDrag(mSurfaceSession, callerPid, callerUid, window,
+            return mDragDropController.performDrag(mSurfaceSession, mPid, mUid, window,
                     flags, surface, touchSource, touchX, touchY, thumbCenterX, thumbCenterY, data);
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -625,11 +623,9 @@
 
     public void grantInputChannel(int displayId, SurfaceControl surface,
             IWindow window, IBinder hostInputToken, InputChannel outInputChannel) {
-        final int callerUid = Binder.getCallingUid();
-        final int callerPid = Binder.getCallingPid();
         final long identity = Binder.clearCallingIdentity();
         try {
-            mService.grantInputChannel(callerUid, callerPid, displayId, surface, window,
+            mService.grantInputChannel(mUid, mPid, displayId, surface, window,
                     hostInputToken, outInputChannel);
         } finally {
             Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
index 0d3afc0..1259ee9 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationThread.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.os.Trace;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.ServiceThread;
 
 /**
@@ -56,4 +57,20 @@
             return sHandler;
         }
     }
+
+    /**
+     * Disposes current surface animation thread if it's initialized. Should only be used in tests
+     * to set up a new environment.
+     */
+    @VisibleForTesting
+    public static void dispose() {
+        synchronized (SurfaceAnimationThread.class) {
+            if (sInstance == null) {
+                return;
+            }
+
+            getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
+            sInstance = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 183ca07..b229a1d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2006 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,17 +17,77 @@
 package com.android.server.wm;
 
 import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
 import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
+import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.res.Configuration.EMPTY;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.METADATA_TASK_ID;
 
 import static com.android.server.EventLogTags.WM_TASK_CREATED;
 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;
+import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
+import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
+import static com.android.server.am.TaskRecordProto.STACK_ID;
+import static com.android.server.am.TaskRecordProto.TASK;
+import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
+import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
+import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.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;
@@ -39,32 +99,240 @@
 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
-import android.annotation.CallSuper;
+import static java.lang.Integer.MAX_VALUE;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
+import android.app.ActivityManager.TaskSnapshot;
+import android.app.ActivityOptions;
+import android.app.ActivityTaskManager;
+import android.app.AppGlobals;
+import android.app.TaskInfo;
+import android.app.WindowConfiguration;
+import android.content.ComponentName;
+import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Debug;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
+import android.view.DisplayInfo;
 import android.view.RemoteAnimationTarget;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.ToBooleanFunction;
+import com.android.internal.util.XmlUtils;
+import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.ActivityStack.ActivityState;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Objects;
 import java.util.function.Consumer;
 
-class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener{
-    static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
+class Task extends WindowContainer<ActivityRecord> implements ConfigurationContainerListener {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_ATM;
+    private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
+    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
+    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
+    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
+
+    private static final String ATTR_TASKID = "task_id";
+    private static final String TAG_INTENT = "intent";
+    private static final String TAG_AFFINITYINTENT = "affinity_intent";
+    private static final String ATTR_REALACTIVITY = "real_activity";
+    private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
+    private static final String ATTR_ORIGACTIVITY = "orig_activity";
+    private static final String TAG_ACTIVITY = "activity";
+    private static final String ATTR_AFFINITY = "affinity";
+    private static final String ATTR_ROOT_AFFINITY = "root_affinity";
+    private static final String ATTR_ROOTHASRESET = "root_has_reset";
+    private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
+    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
+    private static final String ATTR_USERID = "user_id";
+    private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
+    private static final String ATTR_EFFECTIVE_UID = "effective_uid";
+    @Deprecated
+    private static final String ATTR_TASKTYPE = "task_type";
+    private static final String ATTR_LASTDESCRIPTION = "last_description";
+    private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
+    private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
+    private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
+    private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
+    private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
+    private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
+    private static final String ATTR_CALLING_UID = "calling_uid";
+    private static final String ATTR_CALLING_PACKAGE = "calling_package";
+    private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
+    private static final String ATTR_RESIZE_MODE = "resize_mode";
+    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
+    private static final String ATTR_MIN_WIDTH = "min_width";
+    private static final String ATTR_MIN_HEIGHT = "min_height";
+    private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
+
+    // Current version of the task record we persist. Used to check if we need to run any upgrade
+    // code.
+    private static final int PERSIST_TASK_VERSION = 1;
+
+    private static final int INVALID_MIN_SIZE = -1;
+
+    /**
+     * The modes to control how the stack is moved to the front when calling {@link Task#reparent}.
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            REPARENT_MOVE_STACK_TO_FRONT,
+            REPARENT_KEEP_STACK_AT_FRONT,
+            REPARENT_LEAVE_STACK_IN_PLACE
+    })
+    @interface ReparentMoveStackMode {}
+    // Moves the stack to the front if it was not at the front
+    static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
+    // Only moves the stack to the front if it was focused or front most already
+    static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
+    // Do not move the stack as a part of reparenting
+    static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
+
+    /**
+     * The factory used to create {@link Task}. This allows OEM subclass {@link Task}.
+     */
+    private static TaskFactory sTaskFactory;
+
+    String affinity;        // The affinity name for this task, or null; may change identity.
+    String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
+    final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
+    final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
+    Intent intent;          // The original intent that started the task. Note that this value can
+                            // be null.
+    Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
+    int effectiveUid;       // The current effective uid of the identity of this task.
+    ComponentName origActivity; // The non-alias activity component of the intent.
+    ComponentName realActivity; // The actual activity component that started the task.
+    boolean realActivitySuspended; // True if the actual activity component that started the
+                                   // task is suspended.
+    boolean inRecents;      // Actually in the recents list?
+    long lastActiveTime;    // Last time this task was active in the current device session,
+                            // including sleep. This time is initialized to the elapsed time when
+                            // restored from disk.
+    boolean isAvailable;    // Is the activity available to be launched?
+    boolean rootWasReset;   // True if the intent at the root of the task had
+                            // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
+    boolean autoRemoveRecents;  // If true, we should automatically remove the task from
+                                // recents when activity finishes
+    boolean askedCompatMode;// Have asked the user about compat mode for this task.
+    boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
+
+    String stringName;      // caching of toString() result.
+    boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
+                                // was changed.
+
+    int numFullscreen;      // Number of fullscreen activities.
+
+    /** Can't be put in lockTask mode. */
+    final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
+    /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
+    final static int LOCK_TASK_AUTH_PINNABLE = 1;
+    /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
+    final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
+    /** Can enter lockTask without user approval. Can start over existing lockTask task. */
+    final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+    /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+     * lockTask task. */
+    final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
+    int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+
+    int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
+
+    /** Current stack. Setter must always be used to update the value. */
+    private ActivityStack mStack;
+
+    /** The process that had previously hosted the root activity of this task.
+     * Used to know that we should try harder to keep this process around, in case the
+     * user wants to return to it. */
+    private WindowProcessController mRootProcess;
+
+    /** Takes on same value as first root activity */
+    boolean isPersistable = false;
+    int maxRecents;
+
+    /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
+     * determining the order when restoring. Sign indicates whether last task movement was to front
+     * (positive) or back (negative). Absolute value indicates time. */
+    long mLastTimeMoved;
+
+    /** If original intent did not allow relinquishing task identity, save that information */
+    private boolean mNeverRelinquishIdentity = true;
+
+    // Used in the unique case where we are clearing the task in order to reuse it. In that case we
+    // do not want to delete the stack when the task goes empty.
+    private boolean mReuseTask = false;
+
+    CharSequence lastDescription; // Last description captured for this item.
+
+    int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
+    int mAffiliatedTaskColor; // color of the parent task affiliation.
+    Task mPrevAffiliate; // previous task in affiliated chain.
+    int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
+    Task mNextAffiliate; // next task in affiliated chain.
+    int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
+
+    // For relaunching the task from recents as though it was launched by the original launcher.
+    int mCallingUid;
+    String mCallingPackage;
+
+    private final Rect mTmpStableBounds = new Rect();
+    private final Rect mTmpNonDecorBounds = new Rect();
+    private final Rect mTmpBounds = new Rect();
+    private final Rect mTmpInsets = new Rect();
+
+    // Last non-fullscreen bounds the task was launched in or resized to.
+    // The information is persisted and used to determine the appropriate stack to launch the
+    // task into on restore.
+    Rect mLastNonFullscreenBounds = null;
+    // Minimal width and height of this task when it's resizeable. -1 means it should use the
+    // default minimal width/height.
+    int mMinWidth;
+    int mMinHeight;
+
+    // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
+    // This number will be assigned when we evaluate OOM scores for all visible tasks.
+    int mLayerRank = -1;
+
+    /** Helper object used for updating override configuration. */
+    private Configuration mTmpConfig = new Configuration();
+
+    /** Used by fillTaskInfo */
+    final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
 
     final ActivityTaskManagerService mAtmService;
 
@@ -122,22 +390,1843 @@
     /** @see #setCanAffectSystemUiFlags */
     private boolean mCanAffectSystemUiFlags = true;
 
-    Task(int taskId, TaskStack stack, int userId, int resizeMode, boolean supportsPictureInPicture,
-            TaskDescription taskDescription, ActivityTaskManagerService atm) {
-        super(atm.mWindowManager);
-        mAtmService = atm;
-        mTaskId = taskId;
-        mUserId = userId;
+    /**
+     * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
+     * ActivityInfo, Intent, TaskDescription)} instead.
+     */
+    Task(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            TaskDescription _taskDescription, ActivityStack stack) {
+        this(atmService, _taskId, _intent,  null /*_affinityIntent*/, null /*_affinity*/,
+                null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
+                false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
+                UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
+                null /*_lastDescription*/, System.currentTimeMillis(),
+                true /*neverRelinquishIdentity*/,
+                _taskDescription != null ? _taskDescription : new TaskDescription(),
+                _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
+                info.applicationInfo.uid, info.packageName, info.resizeMode,
+                info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
+                false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
+                _voiceSession, _voiceInteractor, stack);
+    }
+
+    /** Don't use constructor directly. This is only used by XML parser. */
+    Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
+            Intent _affinityIntent, String _affinity, String _rootAffinity,
+            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
+            boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
+            int _effectiveUid, String _lastDescription,
+            long lastTimeMoved, boolean neverRelinquishIdentity,
+            TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
+            int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+            int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
+            boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
+            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
+            ActivityStack stack) {
+        super(atmService.mWindowManager);
+
+        EventLog.writeEvent(WM_TASK_CREATED, _taskId,
+                stack != null ? stack.mStackId : INVALID_STACK_ID);
+        mAtmService = atmService;
+        mTaskId = _taskId;
+        mUserId = _userId;
         mResizeMode = resizeMode;
         mSupportsPictureInPicture = supportsPictureInPicture;
-        mTaskDescription = taskDescription;
-        EventLog.writeEvent(WM_TASK_CREATED, mTaskId,
-                stack != null ? stack.mStackId : INVALID_STACK_ID);
-
+        mTaskDescription = _lastTaskDescription;
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
         setOrientation(SCREEN_ORIENTATION_UNSET);
-        // TODO(task-merge): Is this really needed?
-        //setBounds(getResolvedOverrideBounds());
+        mRemoteToken = new RemoteToken(this);
+        affinityIntent = _affinityIntent;
+        affinity = _affinity;
+        rootAffinity = _rootAffinity;
+        voiceSession = _voiceSession;
+        voiceInteractor = _voiceInteractor;
+        realActivity = _realActivity;
+        realActivitySuspended = _realActivitySuspended;
+        origActivity = _origActivity;
+        rootWasReset = _rootWasReset;
+        isAvailable = true;
+        autoRemoveRecents = _autoRemoveRecents;
+        askedCompatMode = _askedCompatMode;
+        mUserSetupComplete = userSetupComplete;
+        effectiveUid = _effectiveUid;
+        touchActiveTime();
+        lastDescription = _lastDescription;
+        mLastTimeMoved = lastTimeMoved;
+        mNeverRelinquishIdentity = neverRelinquishIdentity;
+        mAffiliatedTaskId = taskAffiliation;
+        mAffiliatedTaskColor = taskAffiliationColor;
+        mPrevAffiliateTaskId = prevTaskId;
+        mNextAffiliateTaskId = nextTaskId;
+        mCallingUid = callingUid;
+        mCallingPackage = callingPackage;
+        mResizeMode = resizeMode;
+        if (info != null) {
+            setIntent(_intent, info);
+            setMinDimensions(info);
+        } else {
+            intent = _intent;
+            mMinWidth = minWidth;
+            mMinHeight = minHeight;
+        }
+        mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
+    }
+
+    void cleanUpResourcesForDestroy() {
+        if (hasChild()) {
+            return;
+        }
+
+        // This task is going away, so save the last state if necessary.
+        saveLaunchingStateIfNeeded();
+
+        // TODO: VI what about activity?
+        final boolean isVoiceSession = voiceSession != null;
+        if (isVoiceSession) {
+            try {
+                voiceSession.taskFinished(intent, mTaskId);
+            } catch (RemoteException e) {
+            }
+        }
+        if (autoRemoveFromRecents() || isVoiceSession) {
+            // Task creator asked to remove this when done, or this task was a voice
+            // interaction, so it should not remain on the recent tasks list.
+            mAtmService.mStackSupervisor.mRecentTasks.remove(this);
+        }
+
+        removeIfPossible();
+    }
+
+    @VisibleForTesting
+    @Override
+    void removeIfPossible() {
+        mAtmService.getLockTaskController().clearLockedTask(this);
+        if (shouldDeferRemoval()) {
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
+            return;
+        }
+        removeImmediately();
+        mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
+    }
+
+    void setResizeMode(int resizeMode) {
+        if (mResizeMode == resizeMode) {
+            return;
+        }
+        mResizeMode = resizeMode;
+        mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
+        mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+        updateTaskDescription();
+    }
+
+    boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
+        mAtmService.deferWindowLayout();
+
+        try {
+            final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
+
+            if (getParent() == null) {
+                // Task doesn't exist in window manager yet (e.g. was restored from recents).
+                // All we can do for now is update the bounds so it can be used when the task is
+                // added to window manager.
+                setBounds(bounds);
+                if (!inFreeformWindowingMode()) {
+                    // re-restore the task so it can have the proper stack association.
+                    mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
+                }
+                return true;
+            }
+
+            if (!canResizeToBounds(bounds)) {
+                throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
+                        + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
+            }
+
+            // Do not move the task to another stack here.
+            // This method assumes that the task is already placed in the right stack.
+            // we do not mess with that decision and we only do the resize!
+
+            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
+
+            boolean updatedConfig = false;
+            mTmpConfig.setTo(getResolvedOverrideConfiguration());
+            if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
+                updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
+            }
+            // This variable holds information whether the configuration didn't change in a
+            // significant way and the activity was kept the way it was. If it's false, it means
+            // the activity had to be relaunched due to configuration change.
+            boolean kept = true;
+            if (updatedConfig) {
+                final ActivityRecord r = topRunningActivityLocked();
+                if (r != null && !deferResume) {
+                    kept = r.ensureActivityConfiguration(0 /* globalChanges */,
+                            preserveWindow);
+                    // Preserve other windows for resizing because if resizing happens when there
+                    // is a dialog activity in the front, the activity that still shows some
+                    // content to the user will become black and cause flickers. Note in most cases
+                    // this won't cause tons of irrelevant windows being preserved because only
+                    // activities in this task may experience a bounds change. Configs for other
+                    // activities stay the same.
+                    mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0,
+                            preserveWindow);
+                    if (!kept) {
+                        mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
+                    }
+                }
+            }
+            resize(kept, forced);
+
+            saveLaunchingStateIfNeeded();
+
+            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+            return kept;
+        } finally {
+            mAtmService.continueWindowLayout();
+        }
+    }
+
+    /** Convenience method to reparent a task to the top or bottom position of the stack. */
+    boolean reparent(ActivityStack preferredStack, boolean toTop,
+            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+            String reason) {
+        return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
+                true /* schedulePictureInPictureModeChange */, reason);
+    }
+
+    /**
+     * Convenience method to reparent a task to the top or bottom position of the stack, with
+     * an option to skip scheduling the picture-in-picture mode change.
+     */
+    boolean reparent(ActivityStack preferredStack, boolean toTop,
+            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+            boolean schedulePictureInPictureModeChange, String reason) {
+        return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
+                deferResume, schedulePictureInPictureModeChange, reason);
+    }
+
+    /** Convenience method to reparent a task to a specific position of the stack. */
+    boolean reparent(ActivityStack preferredStack, int position,
+            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+            String reason) {
+        return reparent(preferredStack, position, moveStackMode, animate, deferResume,
+                true /* schedulePictureInPictureModeChange */, reason);
+    }
+
+    /**
+     * Reparents the task into a preferred stack, creating it if necessary.
+     *
+     * @param preferredStack the target stack to move this task
+     * @param position the position to place this task in the new stack
+     * @param animate whether or not we should wait for the new window created as a part of the
+     *            reparenting to be drawn and animated in
+     * @param moveStackMode whether or not to move the stack to the front always, only if it was
+     *            previously focused & in front, or never
+     * @param deferResume whether or not to update the visibility of other tasks and stacks that may
+     *            have changed as a result of this reparenting
+     * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
+     *            change. Callers may set this to false if they are explicitly scheduling PiP mode
+     *            changes themselves, like during the PiP animation
+     * @param reason the caller of this reparenting
+     * @return whether the task was reparented
+     */
+    // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
+    // re-parenting the task. Can only be done when we are no longer using static stack Ids.
+    boolean reparent(ActivityStack preferredStack, int position,
+            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
+            boolean schedulePictureInPictureModeChange, String reason) {
+        final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
+        final RootActivityContainer root = mAtmService.mRootActivityContainer;
+        final WindowManagerService windowManager = mAtmService.mWindowManager;
+        final ActivityStack sourceStack = getStack();
+        final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
+                position == MAX_VALUE);
+        if (toStack == sourceStack) {
+            return false;
+        }
+        if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
+            return false;
+        }
+
+        final boolean toTopOfStack = position == MAX_VALUE;
+        if (toTopOfStack && toStack.getResumedActivity() != null
+                && toStack.topRunningActivityLocked() != null) {
+            // Pause the resumed activity on the target stack while re-parenting task on top of it.
+            toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
+                    null /* resuming */);
+        }
+
+        final int toStackWindowingMode = toStack.getWindowingMode();
+        final ActivityRecord topActivity = getTopActivity();
+
+        final boolean mightReplaceWindow = topActivity != null
+                && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
+        if (mightReplaceWindow) {
+            // We are about to relaunch the activity because its configuration changed due to
+            // being maximized, i.e. size change. The activity will first remove the old window
+            // and then add a new one. This call will tell window manager about this, so it can
+            // preserve the old window until the new one is drawn. This prevents having a gap
+            // between the removal and addition, in which no window is visible. We also want the
+            // entrance of the new window to be properly animated.
+            // Note here we always set the replacing window first, as the flags might be needed
+            // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
+            windowManager.setWillReplaceWindow(topActivity.appToken, animate);
+        }
+
+        mAtmService.deferWindowLayout();
+        boolean kept = true;
+        try {
+            final ActivityRecord r = topRunningActivityLocked();
+            final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
+                    && (topRunningActivityLocked() == r);
+            final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
+            final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
+
+            // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+            // Whenever we are moving the top activity from the front stack we want to make sure to
+            // move the stack to the front.
+            final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
+                    && (sourceStack.topRunningActivityLocked() == r);
+
+            final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
+                    || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
+
+            reparent(toStack, position, moveStackToFront, reason);
+
+            if (schedulePictureInPictureModeChange) {
+                // Notify of picture-in-picture mode changes
+                supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
+            }
+
+            // If the task had focus before (or we're requested to move focus), move focus to the
+            // new stack by moving the stack to the front.
+            if (r != null) {
+                toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
+                        wasPaused, reason);
+            }
+            if (!animate) {
+                mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
+            }
+
+            // We might trigger a configuration change. Save the current task bounds for freezing.
+            // TODO: Should this call be moved inside the resize method in WM?
+            toStack.prepareFreezingTaskBounds();
+
+            // Make sure the task has the appropriate bounds/size for the stack it is in.
+            final boolean toStackSplitScreenPrimary =
+                    toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+            final Rect configBounds = getRequestedOverrideBounds();
+            if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
+                    || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
+                    && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
+                kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
+                        !mightReplaceWindow, deferResume);
+            } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
+                Rect bounds = getLaunchBounds();
+                if (bounds == null) {
+                    mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+                    bounds = configBounds;
+                }
+                kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
+            } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
+                if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
+                    // Move recents to front so it is not behind home stack when going into docked
+                    // mode
+                    mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
+                }
+                kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
+                        !mightReplaceWindow, deferResume);
+            }
+        } finally {
+            mAtmService.continueWindowLayout();
+        }
+
+        if (mightReplaceWindow) {
+            // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
+            // window), we need to clear the replace window settings. Otherwise, we schedule a
+            // timeout to remove the old window if the replacing window is not coming in time.
+            windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
+        }
+
+        if (!deferResume) {
+            // The task might have already been running and its visibility needs to be synchronized
+            // with the visibility of the stack / windows.
+            root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
+            root.resumeFocusedStacksTopActivities();
+        }
+
+        // TODO: Handle incorrect request to move before the actual move, not after.
+        supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
+                DEFAULT_DISPLAY, toStack);
+
+        return (preferredStack == toStack);
+    }
+
+    /**
+     * @return {@code true} if the windows of tasks being moved to the target stack from the
+     * source stack should be replaced, meaning that window manager will keep the old window
+     * around until the new is ready.
+     */
+    private static boolean replaceWindowsOnTaskMove(
+            int sourceWindowingMode, int targetWindowingMode) {
+        return sourceWindowingMode == WINDOWING_MODE_FREEFORM
+                || targetWindowingMode == WINDOWING_MODE_FREEFORM;
+    }
+
+    /**
+     * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
+     */
+    TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
+
+        // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
+        // synchronized between AM and WM.
+        return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
+                restoreFromDisk);
+    }
+
+    void touchActiveTime() {
+        lastActiveTime = SystemClock.elapsedRealtime();
+    }
+
+    long getInactiveDuration() {
+        return SystemClock.elapsedRealtime() - lastActiveTime;
+    }
+
+    /** Sets the original intent, and the calling uid and package. */
+    void setIntent(ActivityRecord r) {
+        mCallingUid = r.launchedFromUid;
+        mCallingPackage = r.launchedFromPackage;
+        setIntent(r.intent, r.info);
+        setLockTaskAuth(r);
+    }
+
+    /** Sets the original intent, _without_ updating the calling uid or package. */
+    private void setIntent(Intent _intent, ActivityInfo info) {
+        if (intent == null) {
+            mNeverRelinquishIdentity =
+                    (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+        } else if (mNeverRelinquishIdentity) {
+            return;
+        }
+
+        affinity = info.taskAffinity;
+        if (intent == null) {
+            // If this task already has an intent associated with it, don't set the root
+            // affinity -- we don't want it changing after initially set, but the initially
+            // set value may be null.
+            rootAffinity = affinity;
+        }
+        effectiveUid = info.applicationInfo.uid;
+        stringName = null;
+
+        if (info.targetActivity == null) {
+            if (_intent != null) {
+                // If this Intent has a selector, we want to clear it for the
+                // recent task since it is not relevant if the user later wants
+                // to re-launch the app.
+                if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
+                    _intent = new Intent(_intent);
+                    _intent.setSelector(null);
+                    _intent.setSourceBounds(null);
+                }
+            }
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
+            intent = _intent;
+            realActivity = _intent != null ? _intent.getComponent() : null;
+            origActivity = null;
+        } else {
+            ComponentName targetComponent = new ComponentName(
+                    info.packageName, info.targetActivity);
+            if (_intent != null) {
+                Intent targetIntent = new Intent(_intent);
+                targetIntent.setSelector(null);
+                targetIntent.setSourceBounds(null);
+                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                        "Setting Intent of " + this + " to target " + targetIntent);
+                intent = targetIntent;
+                realActivity = targetComponent;
+                origActivity = _intent.getComponent();
+            } else {
+                intent = null;
+                realActivity = targetComponent;
+                origActivity = new ComponentName(info.packageName, info.name);
+            }
+        }
+
+        final int intentFlags = intent == null ? 0 : intent.getFlags();
+        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+            // Once we are set to an Intent with this flag, we count this
+            // task as having a true root activity.
+            rootWasReset = true;
+        }
+        mUserId = UserHandle.getUserId(info.applicationInfo.uid);
+        mUserSetupComplete = Settings.Secure.getIntForUser(
+                mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
+        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
+            // If the activity itself has requested auto-remove, then just always do it.
+            autoRemoveRecents = true;
+        } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
+                == FLAG_ACTIVITY_NEW_DOCUMENT) {
+            // If the caller has not asked for the document to be retained, then we may
+            // want to turn on auto-remove, depending on whether the target has set its
+            // own document launch mode.
+            if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
+                autoRemoveRecents = false;
+            } else {
+                autoRemoveRecents = true;
+            }
+        } else {
+            autoRemoveRecents = false;
+        }
+        if (mResizeMode != info.resizeMode) {
+            mResizeMode = info.resizeMode;
+            updateTaskDescription();
+        }
+        mSupportsPictureInPicture = info.supportsPictureInPicture();
+    }
+
+    /** Sets the original minimal width and height. */
+    private void setMinDimensions(ActivityInfo info) {
+        if (info != null && info.windowLayout != null) {
+            mMinWidth = info.windowLayout.minWidth;
+            mMinHeight = info.windowLayout.minHeight;
+        } else {
+            mMinWidth = INVALID_MIN_SIZE;
+            mMinHeight = INVALID_MIN_SIZE;
+        }
+    }
+
+    /**
+     * Return true if the input activity has the same intent filter as the intent this task
+     * record is based on (normally the root activity intent).
+     */
+    boolean isSameIntentFilter(ActivityRecord r) {
+        final Intent intent = new Intent(r.intent);
+        // Make sure the component are the same if the input activity has the same real activity
+        // as the one in the task because either one of them could be the alias activity.
+        if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
+            intent.setComponent(this.intent.getComponent());
+        }
+        return intent.filterEquals(this.intent);
+    }
+
+    boolean returnsToHomeStack() {
+        final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
+        return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
+    }
+
+    void setPrevAffiliate(Task prevAffiliate) {
+        mPrevAffiliate = prevAffiliate;
+        mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
+    }
+
+    void setNextAffiliate(Task nextAffiliate) {
+        mNextAffiliate = nextAffiliate;
+        mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
+    }
+
+    ActivityStack getStack() {
+        return mStack;
+    }
+
+    @Override
+    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
+        final ActivityStack oldStack = ((ActivityStack) oldParent);
+        final ActivityStack newStack = ((ActivityStack) newParent);
+
+        mStack = newStack;
+
+        super.onParentChanged(newParent, oldParent);
+
+        if (oldStack != null) {
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityRecord activity = getChildAt(i);
+                oldStack.onActivityRemovedFromStack(activity);
+            }
+
+            if (oldStack.inPinnedWindowingMode()
+                    && (newStack == null || !newStack.inPinnedWindowingMode())) {
+                // Notify if a task from the pinned stack is being removed
+                // (or moved depending on the mode).
+                mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
+            }
+        }
+
+        if (newStack != null) {
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                final ActivityRecord activity = getChildAt(i);
+                newStack.onActivityAddedToStack(activity);
+            }
+
+            // TODO: Ensure that this is actually necessary here
+            // Notify the voice session if required
+            if (voiceSession != null) {
+                try {
+                    voiceSession.taskStarted(intent, mTaskId);
+                } catch (RemoteException e) {
+                }
+            }
+        }
+
+        // First time we are adding the task to the system.
+        if (oldParent == null && newParent != null) {
+
+            // TODO: Super random place to be doing this, but aligns with what used to be done
+            // before we unified Task level. Look into if this can be done in a better place.
+            updateOverrideConfigurationFromLaunchBounds();
+        }
+
+        // Task is being removed.
+        if (oldParent != null && newParent == null) {
+            cleanUpResourcesForDestroy();
+        }
+
+
+        // Update task bounds if needed.
+        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
+
+        if (getWindowConfiguration().windowsAreScaleable()) {
+            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
+            // while a resize is pending.
+            forceWindowsScaleable(true /* force */);
+        } else {
+            forceWindowsScaleable(false /* force */);
+        }
+
+        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+    }
+
+    void updateTaskMovement(boolean toFront) {
+        if (isPersistable) {
+            mLastTimeMoved = System.currentTimeMillis();
+            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
+            // recently will be most negative, tasks sent to the bottom before that will be less
+            // negative. Similarly for recent tasks moved to the top which will be most positive.
+            if (!toFront) {
+                mLastTimeMoved *= -1;
+            }
+        }
+        mAtmService.mRootActivityContainer.invalidateTaskLayers();
+    }
+
+    /**
+     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
+     */
+    int getStackId() {
+        return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
+    }
+
+    // Close up recents linked list.
+    private void closeRecentsChain() {
+        if (mPrevAffiliate != null) {
+            mPrevAffiliate.setNextAffiliate(mNextAffiliate);
+        }
+        if (mNextAffiliate != null) {
+            mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
+        }
+        setPrevAffiliate(null);
+        setNextAffiliate(null);
+    }
+
+    void removedFromRecents() {
+        closeRecentsChain();
+        if (inRecents) {
+            inRecents = false;
+            mAtmService.notifyTaskPersisterLocked(this, false);
+        }
+
+        clearRootProcess();
+
+        mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
+                mTaskId, mUserId);
+    }
+
+    void setTaskToAffiliateWith(Task taskToAffiliateWith) {
+        closeRecentsChain();
+        mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
+        mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
+        // Find the end
+        while (taskToAffiliateWith.mNextAffiliate != null) {
+            final Task nextRecents = taskToAffiliateWith.mNextAffiliate;
+            if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
+                Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
+                        + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
+                if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
+                    nextRecents.setPrevAffiliate(null);
+                }
+                taskToAffiliateWith.setNextAffiliate(null);
+                break;
+            }
+            taskToAffiliateWith = nextRecents;
+        }
+        taskToAffiliateWith.setNextAffiliate(this);
+        setPrevAffiliate(taskToAffiliateWith);
+        setNextAffiliate(null);
+    }
+
+    /** Returns the intent for the root activity for this task */
+    Intent getBaseIntent() {
+        return intent != null ? intent : affinityIntent;
+    }
+
+    /** Returns the first non-finishing activity from the bottom. */
+    ActivityRecord getRootActivity() {
+        final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
+        if (rootActivityIndex == -1) {
+            // There are no non-finishing activities in the task.
+            return null;
+        }
+        return getChildAt(rootActivityIndex);
+    }
+
+    ActivityRecord getTopActivity() {
+        return getTopActivity(true /* includeOverlays */);
+    }
+
+    ActivityRecord getTopActivity(boolean includeOverlays) {
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityRecord r = getChildAt(i);
+            if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
+                continue;
+            }
+            return r;
+        }
+        return null;
+    }
+
+    ActivityRecord topRunningActivityLocked() {
+        if (mStack != null) {
+            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = getChildAt(activityNdx);
+                if (!r.finishing && r.okToShowLocked()) {
+                    return r;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return true if any activities in this task belongs to input uid.
+     */
+    boolean containsAppUid(int uid) {
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityRecord r = getChildAt(i);
+            if (r.getUid() == uid) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
+        if (mStack != null) {
+            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = getChildAt(activityNdx);
+                if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
+                    outActivities.add(r);
+                }
+            }
+        }
+    }
+
+    ActivityRecord topRunningActivityWithStartingWindowLocked() {
+        if (mStack != null) {
+            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+                ActivityRecord r = getChildAt(activityNdx);
+                if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
+                        || r.finishing || !r.okToShowLocked()) {
+                    continue;
+                }
+                return r;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return the number of running activities, and the number of non-finishing/initializing
+     * activities in the provided {@param reportOut} respectively.
+     */
+    void getNumRunningActivities(TaskActivitiesReport reportOut) {
+        reportOut.reset();
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            final ActivityRecord r = getChildAt(i);
+            if (r.finishing) {
+                continue;
+            }
+
+            reportOut.base = r;
+
+            // Increment the total number of non-finishing activities
+            reportOut.numActivities++;
+
+            if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
+                reportOut.top = r;
+                // Reset the number of running activities until we hit the first non-initializing
+                // activity
+                reportOut.numRunning = 0;
+            }
+            if (r.attachedToProcess()) {
+                // Increment the number of actually running activities
+                reportOut.numRunning++;
+            }
+        }
+    }
+
+    boolean okToShowLocked() {
+        // NOTE: If {@link Task#topRunningActivity} return is not null then it is
+        // okay to show the activity when locked.
+        return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
+                || topRunningActivityLocked() != null;
+    }
+
+    /**
+     * Reorder the history stack so that the passed activity is brought to the front.
+     */
+    final void moveActivityToFrontLocked(ActivityRecord newTop) {
+        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
+                + newTop + " to stack at top callers=" + Debug.getCallers(4));
+
+        positionChildAtTop(newTop);
+        updateEffectiveIntent();
+    }
+
+    @Override
+    public int getActivityType() {
+        final int applicationType = super.getActivityType();
+        if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
+            return applicationType;
+        }
+        return getChildAt(0).getActivityType();
+    }
+
+    @Override
+    void addChild(ActivityRecord r, int index) {
+        // If this task had any child before we added this one.
+        boolean hadChild = hasChild();
+
+        index = getAdjustedAddPosition(r, index);
+        super.addChild(r, index);
+
+        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
+        r.inHistory = true;
+
+        if (r.occludesParent()) {
+            numFullscreen++;
+        }
+        // Only set this based on the first activity
+        if (!hadChild) {
+            if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
+                // Normally non-standard activity type for the activity record will be set when the
+                // object is created, however we delay setting the standard application type until
+                // this point so that the task can set the type for additional activities added in
+                // the else condition below.
+                r.setActivityType(ACTIVITY_TYPE_STANDARD);
+            }
+            setActivityType(r.getActivityType());
+            isPersistable = r.isPersistable();
+            mCallingUid = r.launchedFromUid;
+            mCallingPackage = r.launchedFromPackage;
+            // Clamp to [1, max].
+            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
+                    ActivityTaskManager.getMaxAppRecentsLimitStatic());
+        } else {
+            // Otherwise make all added activities match this one.
+            r.setActivityType(getActivityType());
+        }
+
+        updateEffectiveIntent();
+        if (r.isPersistable()) {
+            mAtmService.notifyTaskPersisterLocked(this, false);
+        }
+
+        // Make sure the list of display UID whitelists is updated
+        // now that this record is in a new task.
+        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
+    }
+
+    void addChild(ActivityRecord r) {
+        addChild(r, Integer.MAX_VALUE /* add on top */);
+    }
+
+    @Override
+    void removeChild(ActivityRecord r) {
+        if (!mChildren.contains(r)) {
+            Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
+            return;
+        }
+
+        super.removeChild(r);
+        if (r.occludesParent()) {
+            numFullscreen--;
+        }
+        if (r.isPersistable()) {
+            mAtmService.notifyTaskPersisterLocked(this, false);
+        }
+
+        if (inPinnedWindowingMode()) {
+            // We normally notify listeners of task stack changes on pause, however pinned stack
+            // activities are normally in the paused state so no notification will be sent there
+            // before the activity is removed. We send it here so instead.
+            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
+        }
+
+        final String reason = "removeChild";
+        if (hasChild()) {
+            updateEffectiveIntent();
+
+            // The following block can be executed multiple times if there is more than one overlay.
+            // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
+            // of the task by id and exiting early if not found.
+            if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
+                // When destroying a task, tell the supervisor to remove it so that any activity it
+                // has can be cleaned up correctly. This is currently the only place where we remove
+                // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
+                // state into removeChild(), we just clear the task here before the other residual
+                // work.
+                // TODO: If the callers to removeChild() changes such that we have multiple places
+                //       where we are destroying the task, move this back into removeChild()
+                mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
+                        !REMOVE_FROM_RECENTS, reason);
+            }
+        } else if (!mReuseTask) {
+            // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
+            mStack.removeChild(this, reason);
+            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
+                    "removeChild: last r=" + r + " in t=" + this);
+            removeIfPossible();
+        }
+    }
+
+    /**
+     * @return whether or not there are ONLY task overlay activities in the stack.
+     *         If {@param excludeFinishing} is set, then ignore finishing activities in the check.
+     *         If there are no task overlay activities, this call returns false.
+     */
+    boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
+        int count = 0;
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            final ActivityRecord r = getChildAt(i);
+            if (excludeFinishing && r.finishing) {
+                continue;
+            }
+            if (!r.mTaskOverlay) {
+                return false;
+            }
+            count++;
+        }
+        return count > 0;
+    }
+
+    boolean autoRemoveFromRecents() {
+        // We will automatically remove the task either if it has explicitly asked for
+        // this, or it is empty and has never contained an activity that got shown to
+        // the user.
+        return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
+    }
+
+    /**
+     * Completely remove all activities associated with an existing
+     * task starting at a specified index.
+     */
+    private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
+        int numActivities = getChildCount();
+        for ( ; activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = getChildAt(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if (mStack == null) {
+                // Task was restored from persistent storage.
+                r.takeFromHistory();
+                removeChild(r);
+                --activityNdx;
+                --numActivities;
+            } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
+                    false /* oomAdj */)
+                    == FINISH_RESULT_REMOVED) {
+                --activityNdx;
+                --numActivities;
+            }
+        }
+    }
+
+    /**
+     * Completely remove all activities associated with an existing task.
+     */
+    void performClearTaskLocked() {
+        mReuseTask = true;
+        performClearTaskAtIndexLocked(0, "clear-task-all");
+        mReuseTask = false;
+    }
+
+    ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
+        mReuseTask = true;
+        final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
+        mReuseTask = false;
+        return result;
+    }
+
+    /**
+     * Perform clear operation as requested by
+     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
+     * stack to the given task, then look for
+     * an instance of that activity in the stack and, if found, finish all
+     * activities on top of it and return the instance.
+     *
+     * @param newR Description of the new activity being started.
+     * @return Returns the old activity that should be continued to be used,
+     * or {@code null} if none was found.
+     */
+    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
+        int numActivities = getChildCount();
+        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord r = getChildAt(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            if (r.mActivityComponent.equals(newR.mActivityComponent)) {
+                // Here it is!  Now finish everything in front...
+                final ActivityRecord ret = r;
+
+                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
+                    r = getChildAt(activityNdx);
+                    if (r.finishing) {
+                        continue;
+                    }
+                    ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
+                    if (opts != null) {
+                        ret.updateOptionsLocked(opts);
+                    }
+                    if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
+                            == FINISH_RESULT_REMOVED) {
+                        --activityNdx;
+                        --numActivities;
+                    }
+                }
+
+                // Finally, if this is a normal launch mode (that is, not
+                // expecting onNewIntent()), then we will finish the current
+                // instance of the activity so a new fresh one can be started.
+                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
+                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
+                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
+                    if (!ret.finishing) {
+                        ret.finishIfPossible("clear-task-top", false /* oomAdj */);
+                        return null;
+                    }
+                }
+
+                return ret;
+            }
+        }
+
+        return null;
+    }
+
+    void removeTaskActivitiesLocked(String reason) {
+        // Just remove the entire task.
+        performClearTaskAtIndexLocked(0, reason);
+    }
+
+    String lockTaskAuthToString() {
+        switch (mLockTaskAuth) {
+            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
+            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
+            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
+            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
+            default: return "unknown=" + mLockTaskAuth;
+        }
+    }
+
+    void setLockTaskAuth() {
+        setLockTaskAuth(getRootActivity());
+    }
+
+    private void setLockTaskAuth(@Nullable ActivityRecord r) {
+        if (r == null) {
+            mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
+            return;
+        }
+
+        final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
+        final LockTaskController lockTaskController = mAtmService.getLockTaskController();
+        switch (r.lockTaskLaunchMode) {
+            case LOCK_TASK_LAUNCH_MODE_DEFAULT:
+                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+                        ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
+                break;
+
+            case LOCK_TASK_LAUNCH_MODE_NEVER:
+                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
+                break;
+
+            case LOCK_TASK_LAUNCH_MODE_ALWAYS:
+                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+                break;
+
+            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
+                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
+                        ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
+                break;
+        }
+        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this
+                + " mLockTaskAuth=" + lockTaskAuthToString());
+    }
+
+    @Override
+    public boolean supportsSplitScreenWindowingMode() {
+        // A task can not be docked even if it is considered resizeable because it only supports
+        // picture-in-picture mode but has a non-resizeable resizeMode
+        return super.supportsSplitScreenWindowingMode()
+                // TODO(task-group): Probably makes sense to move this and associated code into
+                // WindowContainer so it affects every node.
+                && mAtmService.mSupportsSplitScreenMultiWindow
+                && (mAtmService.mForceResizableActivities
+                        || (isResizeable(false /* checkSupportsPip */)
+                                && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
+    }
+
+    /**
+     * Check whether this task can be launched on the specified display.
+     *
+     * @param displayId Target display id.
+     * @return {@code true} if either it is the default display or this activity can be put on a
+     *         secondary display.
+     */
+    boolean canBeLaunchedOnDisplay(int displayId) {
+        return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
+                -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
+    }
+
+    /**
+     * Check that a given bounds matches the application requested orientation.
+     *
+     * @param bounds The bounds to be tested.
+     * @return True if the requested bounds are okay for a resizing request.
+     */
+    private boolean canResizeToBounds(Rect bounds) {
+        if (bounds == null || !inFreeformWindowingMode()) {
+            // Note: If not on the freeform workspace, we ignore the bounds.
+            return true;
+        }
+        final boolean landscape = bounds.width() > bounds.height();
+        final Rect configBounds = getRequestedOverrideBounds();
+        if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
+            return configBounds.isEmpty()
+                    || landscape == (configBounds.width() > configBounds.height());
+        }
+        return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
+                && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
+    }
+
+    /**
+     * @return {@code true} if the task is being cleared for the purposes of being reused.
+     */
+    boolean isClearingToReuseTask() {
+        return mReuseTask;
+    }
+
+    /**
+     * Find the activity in the history stack within the given task.  Returns
+     * the index within the history at which it's found, or < 0 if not found.
+     */
+    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
+        final ComponentName realActivity = r.mActivityComponent;
+        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+            ActivityRecord candidate = getChildAt(activityNdx);
+            if (candidate.finishing) {
+                continue;
+            }
+            if (candidate.mActivityComponent.equals(realActivity)) {
+                return candidate;
+            }
+        }
+        return null;
+    }
+
+    /** Updates the last task description values. */
+    void updateTaskDescription() {
+        // TODO(AM refactor): Cleanup to use findRootIndex()
+        // Traverse upwards looking for any break between main task activities and
+        // utility activities.
+        int activityNdx;
+        final int numActivities = getChildCount();
+        final boolean relinquish = numActivities != 0
+                && (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
+        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = getChildAt(activityNdx);
+            if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+                // This will be the top activity for determining taskDescription. Pre-inc to
+                // overcome initial decrement below.
+                ++activityNdx;
+                break;
+            }
+            if (r.intent != null
+                    && (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                break;
+            }
+        }
+        if (activityNdx > 0) {
+            // Traverse downwards starting below break looking for set label, icon.
+            // Note that if there are activities in the task but none of them set the
+            // recent activity values, then we do not fall back to the last set
+            // values in the Task.
+            String label = null;
+            String iconFilename = null;
+            int iconResource = -1;
+            int colorPrimary = 0;
+            int colorBackground = 0;
+            int statusBarColor = 0;
+            int navigationBarColor = 0;
+            boolean statusBarContrastWhenTransparent = false;
+            boolean navigationBarContrastWhenTransparent = false;
+            boolean topActivity = true;
+            for (--activityNdx; activityNdx >= 0; --activityNdx) {
+                final ActivityRecord r = getChildAt(activityNdx);
+                if (r.mTaskOverlay) {
+                    continue;
+                }
+                if (r.taskDescription != null) {
+                    if (label == null) {
+                        label = r.taskDescription.getLabel();
+                    }
+                    if (iconResource == -1) {
+                        iconResource = r.taskDescription.getIconResource();
+                    }
+                    if (iconFilename == null) {
+                        iconFilename = r.taskDescription.getIconFilename();
+                    }
+                    if (colorPrimary == 0) {
+                        colorPrimary = r.taskDescription.getPrimaryColor();
+                    }
+                    if (topActivity) {
+                        colorBackground = r.taskDescription.getBackgroundColor();
+                        statusBarColor = r.taskDescription.getStatusBarColor();
+                        navigationBarColor = r.taskDescription.getNavigationBarColor();
+                        statusBarContrastWhenTransparent =
+                                r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
+                        navigationBarContrastWhenTransparent =
+                                r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
+                    }
+                }
+                topActivity = false;
+            }
+            final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
+                    iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
+                    statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
+                    mResizeMode, mMinWidth, mMinHeight);
+            setTaskDescription(taskDescription);
+            // Update the task affiliation color if we are the parent of the group
+            if (mTaskId == mAffiliatedTaskId) {
+                mAffiliatedTaskColor = taskDescription.getPrimaryColor();
+            }
+            mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
+                    getTaskInfo());
+        }
+    }
+
+    /**
+     * Find the index of the root activity in the task. It will be the first activity from the
+     * bottom that is not finishing.
+     *
+     * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
+     *                      activity that defines the task identity (its base intent). It's the
+     *                      first one that does not have
+     *                      {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
+     * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
+     *         activity was found.
+     */
+    int findRootIndex(boolean effectiveRoot) {
+        int effectiveNdx = -1;
+        final int topActivityNdx = getChildCount() - 1;
+        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
+            final ActivityRecord r = getChildAt(activityNdx);
+            if (r.finishing) {
+                continue;
+            }
+            effectiveNdx = activityNdx;
+            if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+                break;
+            }
+        }
+        return effectiveNdx;
+    }
+
+    // TODO (AM refactor): Invoke automatically when there is a change in children
+    @VisibleForTesting
+    void updateEffectiveIntent() {
+        int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
+        if (effectiveRootIndex == -1) {
+            // All activities in the task are either finishing or relinquish task identity.
+            // But we still want to update the intent, so let's use the bottom activity.
+            effectiveRootIndex = 0;
+        }
+        final ActivityRecord r = getChildAt(effectiveRootIndex);
+        setIntent(r);
+
+        // Update the task description when the activities change
+        updateTaskDescription();
+    }
+
+    void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
+        if (bounds == null) {
+            return;
+        }
+        int minWidth = mMinWidth;
+        int minHeight = mMinHeight;
+        // If the task has no requested minimal size, we'd like to enforce a minimal size
+        // so that the user can not render the task too small to manipulate. We don't need
+        // to do this for the pinned stack as the bounds are controlled by the system.
+        if (!inPinnedWindowingMode() && mStack != null) {
+            final int defaultMinSizeDp =
+                    mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
+            final ActivityDisplay display =
+                    mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
+            final float density =
+                    (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
+            final int defaultMinSize = (int) (defaultMinSizeDp * density);
+
+            if (minWidth == INVALID_MIN_SIZE) {
+                minWidth = defaultMinSize;
+            }
+            if (minHeight == INVALID_MIN_SIZE) {
+                minHeight = defaultMinSize;
+            }
+        }
+        final boolean adjustWidth = minWidth > bounds.width();
+        final boolean adjustHeight = minHeight > bounds.height();
+        if (!(adjustWidth || adjustHeight)) {
+            return;
+        }
+
+        if (adjustWidth) {
+            if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
+                bounds.left = bounds.right - minWidth;
+            } else {
+                // Either left bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping left.
+                bounds.right = bounds.left + minWidth;
+            }
+        }
+        if (adjustHeight) {
+            if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
+                bounds.top = bounds.bottom - minHeight;
+            } else {
+                // Either top bounds match, or neither match, or the previous bounds were
+                // fullscreen and we default to keeping top.
+                bounds.bottom = bounds.top + minHeight;
+            }
+        }
+    }
+
+    void setLastNonFullscreenBounds(Rect bounds) {
+        if (mLastNonFullscreenBounds == null) {
+            mLastNonFullscreenBounds = new Rect(bounds);
+        } else {
+            mLastNonFullscreenBounds.set(bounds);
+        }
+    }
+
+    /**
+     * This should be called when an child activity changes state. This should only
+     * be called from
+     * {@link ActivityRecord#setState(ActivityState, String)} .
+     * @param record The {@link ActivityRecord} whose state has changed.
+     * @param state The new state.
+     * @param reason The reason for the change.
+     */
+    void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
+        final ActivityStack parent = getStack();
+
+        if (parent != null) {
+            parent.onActivityStateChanged(record, state, reason);
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newParentConfig) {
+        // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
+        // restore the last recorded non-fullscreen bounds.
+        final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
+        final boolean nextPersistTaskBounds =
+                getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
+                || newParentConfig.windowConfiguration.persistTaskBounds();
+        if (!prevPersistTaskBounds && nextPersistTaskBounds
+                && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
+            // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
+            getRequestedOverrideConfiguration().windowConfiguration
+                    .setBounds(mLastNonFullscreenBounds);
+        }
+
+        final boolean wasInMultiWindowMode = inMultiWindowMode();
+        super.onConfigurationChanged(newParentConfig);
+        if (wasInMultiWindowMode != inMultiWindowMode()) {
+            mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
+        }
+
+        // If the configuration supports persistent bounds (eg. Freeform), keep track of the
+        // current (non-fullscreen) bounds for persistence.
+        if (getWindowConfiguration().persistTaskBounds()) {
+            final Rect currentBounds = getRequestedOverrideBounds();
+            if (!currentBounds.isEmpty()) {
+                setLastNonFullscreenBounds(currentBounds);
+            }
+        }
+        // TODO: Should also take care of Pip mode changes here.
+
+        saveLaunchingStateIfNeeded();
+    }
+
+    /**
+     * Saves launching state if necessary so that we can launch the activity to its latest state.
+     * It only saves state if this task has been shown to user and it's in fullscreen or freeform
+     * mode on freeform displays.
+     */
+    void saveLaunchingStateIfNeeded() {
+        if (!hasBeenVisible) {
+            // Not ever visible to user.
+            return;
+        }
+
+        final int windowingMode = getWindowingMode();
+        if (windowingMode != WINDOWING_MODE_FULLSCREEN
+                && windowingMode != WINDOWING_MODE_FREEFORM) {
+            return;
+        }
+
+        // Don't persist state if display isn't in freeform mode. Then the task will be launched
+        // back to its last state in a freeform display when it's launched in a freeform display
+        // next time.
+        if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
+            return;
+        }
+
+        // Saves the new state so that we can launch the activity at the same location.
+        mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
+    }
+
+    /**
+     * Adjust bounds to stay within stack bounds.
+     *
+     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
+     * that keep them unchanged, but be contained within the stack bounds.
+     *
+     * @param bounds Bounds to be adjusted.
+     * @param stackBounds Bounds within which the other bounds should remain.
+     * @param overlapPxX The amount of px required to be visible in the X dimension.
+     * @param overlapPxY The amount of px required to be visible in the Y dimension.
+     */
+    private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
+            int overlapPxY) {
+        if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
+            return;
+        }
+
+        // For each side of the parent (eg. left), check if the opposing side of the window (eg.
+        // right) is at least overlap pixels away. If less, offset the window by that difference.
+        int horizontalDiff = 0;
+        // If window is smaller than overlap, use it's smallest dimension instead
+        int overlapLR = Math.min(overlapPxX, bounds.width());
+        if (bounds.right < (stackBounds.left + overlapLR)) {
+            horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
+        } else if (bounds.left > (stackBounds.right - overlapLR)) {
+            horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
+        }
+        int verticalDiff = 0;
+        int overlapTB = Math.min(overlapPxY, bounds.width());
+        if (bounds.bottom < (stackBounds.top + overlapTB)) {
+            verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
+        } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
+            verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
+        }
+        bounds.offset(horizontalDiff, verticalDiff);
+    }
+
+    /**
+     * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
+     * intersectBounds on a side, then the respective side will not be intersected.
+     *
+     * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
+     * inset on that side is no-longer applicable. This scenario happens when a task's minimal
+     * bounds are larger than the provided parent/display bounds.
+     *
+     * @param inOutBounds the bounds to intersect.
+     * @param intersectBounds the bounds to intersect with.
+     * @param intersectInsets insets to apply to intersectBounds before intersecting.
+     */
+    static void intersectWithInsetsIfFits(
+            Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
+        if (inOutBounds.right <= intersectBounds.right) {
+            inOutBounds.right =
+                    Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
+        }
+        if (inOutBounds.bottom <= intersectBounds.bottom) {
+            inOutBounds.bottom =
+                    Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
+        }
+        if (inOutBounds.left >= intersectBounds.left) {
+            inOutBounds.left =
+                    Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
+        }
+        if (inOutBounds.top >= intersectBounds.top) {
+            inOutBounds.top =
+                    Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
+        }
+    }
+
+    /**
+     * Gets bounds with non-decor and stable insets applied respectively.
+     *
+     * If bounds overhangs the display, those edges will not get insets. See
+     * {@link #intersectWithInsetsIfFits}
+     *
+     * @param outNonDecorBounds where to place bounds with non-decor insets applied.
+     * @param outStableBounds where to place bounds with stable insets applied.
+     * @param bounds the bounds to inset.
+     */
+    private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
+            DisplayInfo displayInfo) {
+        outNonDecorBounds.set(bounds);
+        outStableBounds.set(bounds);
+        if (getStack() == null || getStack().getDisplay() == null) {
+            return;
+        }
+        DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
+        if (policy == null) {
+            return;
+        }
+        mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+
+        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
+                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
+        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
+
+        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
+        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
+    }
+
+    /**
+     * Asks docked-divider controller for the smallestwidthdp given bounds.
+     * @param bounds bounds to calculate smallestwidthdp for.
+     */
+    private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
+        DisplayContent dc = mStack.getDisplay().mDisplayContent;
+        if (dc != null) {
+            return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
+        }
+        return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
+    }
+
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig) {
+        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
+    }
+
+    /**
+     * Calculates configuration values used by the client to get resources. This should be run
+     * using app-facing bounds (bounds unmodified by animations or transient interactions).
+     *
+     * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
+     * configuring an "inherit-bounds" window which means that all configuration settings would
+     * just be inherited from the parent configuration.
+     **/
+    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
+            @NonNull Configuration parentConfig,
+            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
+        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
+        }
+
+        float density = inOutConfig.densityDpi;
+        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+            density = parentConfig.densityDpi;
+        }
+        density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
+
+        final Rect bounds = inOutConfig.windowConfiguration.getBounds();
+        Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+        if (outAppBounds == null || outAppBounds.isEmpty()) {
+            inOutConfig.windowConfiguration.setAppBounds(bounds);
+            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
+        }
+        // Non-null compatibility insets means the activity prefers to keep its original size, so
+        // the out bounds doesn't need to be restricted by the parent.
+        final boolean insideParentBounds = compatInsets == null;
+        if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
+            final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
+            if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
+                outAppBounds.intersect(parentAppBounds);
+            }
+        }
+
+        if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
+                || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+            if (insideParentBounds && mStack != null) {
+                final DisplayInfo di = new DisplayInfo();
+                mStack.getDisplay().mDisplay.getDisplayInfo(di);
+
+                // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
+                // area, i.e. the screen area without the system bars.
+                // The non decor inset are areas that could never be removed in Honeycomb. See
+                // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
+                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
+            } else {
+                // Apply the given non-decor and stable insets to calculate the corresponding bounds
+                // for screen size of configuration.
+                int rotation = inOutConfig.windowConfiguration.getRotation();
+                if (rotation == ROTATION_UNDEFINED) {
+                    rotation = parentConfig.windowConfiguration.getRotation();
+                }
+                if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
+                    mTmpNonDecorBounds.set(bounds);
+                    mTmpStableBounds.set(bounds);
+                    compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
+                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
+                            compatInsets.mNonDecorInsets[rotation]);
+                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
+                            compatInsets.mStableInsets[rotation]);
+                    outAppBounds.set(mTmpNonDecorBounds);
+                } else {
+                    // Set to app bounds because it excludes decor insets.
+                    mTmpNonDecorBounds.set(outAppBounds);
+                    mTmpStableBounds.set(outAppBounds);
+                }
+            }
+
+            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
+                final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
+                inOutConfig.screenWidthDp = insideParentBounds
+                        ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
+                        : overrideScreenWidthDp;
+            }
+            if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
+                final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
+                inOutConfig.screenHeightDp = insideParentBounds
+                        ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
+                        : overrideScreenHeightDp;
+            }
+
+            if (inOutConfig.smallestScreenWidthDp
+                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+                if (WindowConfiguration.isFloating(windowingMode)) {
+                    // For floating tasks, calculate the smallest width from the bounds of the task
+                    inOutConfig.smallestScreenWidthDp = (int) (
+                            Math.min(bounds.width(), bounds.height()) / density);
+                } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
+                    // Iterating across all screen orientations, and return the minimum of the task
+                    // width taking into account that the bounds might change because the snap
+                    // algorithm snaps to a different value
+                    inOutConfig.smallestScreenWidthDp =
+                            getSmallestScreenWidthDpForDockedBounds(bounds);
+                }
+                // otherwise, it will just inherit
+            }
+        }
+
+        if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
+            inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
+                    ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
+        }
+        if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
+            // For calculating screen layout, we need to use the non-decor inset screen area for the
+            // calculation for compatibility reasons, i.e. screen area without system bars that
+            // could never go away in Honeycomb.
+            final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
+            final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
+            // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
+            // override calculation with partial default.
+            // Reducing the screen layout starting from its parent config.
+            final int sl = parentConfig.screenLayout
+                    & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
+            final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
+            final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
+            inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
+        }
+    }
+
+    @Override
+    void resolveOverrideConfiguration(Configuration newParentConfig) {
+        mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
+        super.resolveOverrideConfiguration(newParentConfig);
+        int windowingMode =
+                getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
+        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
+            windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
+        }
+        Rect outOverrideBounds =
+                getResolvedOverrideConfiguration().windowConfiguration.getBounds();
+
+        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
+            computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
+                    newParentConfig.windowConfiguration.getBounds(),
+                    newParentConfig.orientation);
+        }
+
+        if (outOverrideBounds.isEmpty()) {
+            // If the task fills the parent, just inherit all the other configs from parent.
+            return;
+        }
+
+        adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
+        if (windowingMode == WINDOWING_MODE_FREEFORM) {
+            // by policy, make sure the window remains within parent somewhere
+            final float density =
+                    ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
+            final Rect parentBounds =
+                    new Rect(newParentConfig.windowConfiguration.getBounds());
+            final ActivityDisplay display = mStack.getDisplay();
+            if (display != null && display.mDisplayContent != null) {
+                // If a freeform window moves below system bar, there is no way to move it again
+                // by touch. Because its caption is covered by system bar. So we exclude them
+                // from stack bounds. and then caption will be shown inside stable area.
+                final Rect stableBounds = new Rect();
+                display.mDisplayContent.getStableRect(stableBounds);
+                parentBounds.intersect(stableBounds);
+            }
+
+            fitWithinBounds(outOverrideBounds, parentBounds,
+                    (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
+                    (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
+
+            // Prevent to overlap caption with stable insets.
+            final int offsetTop = parentBounds.top - outOverrideBounds.top;
+            if (offsetTop > 0) {
+                outOverrideBounds.offset(0, offsetTop);
+            }
+        }
+        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
+    }
+
+    /**
+     * Compute bounds (letterbox or pillarbox) for
+     * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
+     * orientation change and the requested orientation is different from the parent.
+     */
+    void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
+            @NonNull Rect parentBounds, int parentOrientation) {
+        // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
+        outBounds.setEmpty();
+        if (handlesOrientationChangeFromDescendant()) {
+            return;
+        }
+        if (refActivity == null) {
+            // Use the top activity as the reference of orientation. Don't include overlays because
+            // it is usually not the actual content or just temporarily shown.
+            // E.g. ForcedResizableInfoActivity.
+            refActivity = getTopActivity(false /* includeOverlays */);
+        }
+
+        // If the task or the reference activity requires a different orientation (either by
+        // override or activityInfo), make it fit the available bounds by scaling down its bounds.
+        final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
+        final int forcedOrientation =
+                (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
+                        ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
+        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
+            return;
+        }
+
+        final int parentWidth = parentBounds.width();
+        final int parentHeight = parentBounds.height();
+        final float aspect = ((float) parentHeight) / parentWidth;
+        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
+            final int height = (int) (parentWidth / aspect);
+            final int top = parentBounds.centerY() - height / 2;
+            outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
+        } else {
+            final int width = (int) (parentHeight * aspect);
+            final int left = parentBounds.centerX() - width / 2;
+            outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
+        }
+    }
+
+    Rect updateOverrideConfigurationFromLaunchBounds() {
+        final Rect bounds = getLaunchBounds();
+        setBounds(bounds);
+        if (bounds != null && !bounds.isEmpty()) {
+            // TODO: Review if we actually want to do this - we are setting the launch bounds
+            // directly here.
+            bounds.set(getRequestedOverrideBounds());
+        }
+        return bounds;
+    }
+
+    /** Updates the task's bounds and override configuration to match what is expected for the
+     * input stack. */
+    void updateOverrideConfigurationForStack(ActivityStack inStack) {
+        if (mStack != null && mStack == inStack) {
+            return;
+        }
+
+        if (inStack.inFreeformWindowingMode()) {
+            if (!isResizeable()) {
+                throw new IllegalArgumentException("Can not position non-resizeable task="
+                        + this + " in stack=" + inStack);
+            }
+            if (!matchParentBounds()) {
+                return;
+            }
+            if (mLastNonFullscreenBounds != null) {
+                setBounds(mLastNonFullscreenBounds);
+            } else {
+                mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
+            }
+        } else {
+            setBounds(inStack.getRequestedOverrideBounds());
+        }
+    }
+
+    /** Returns the bounds that should be used to launch this task. */
+    Rect getLaunchBounds() {
+        if (mStack == null) {
+            return null;
+        }
+
+        final int windowingMode = getWindowingMode();
+        if (!isActivityTypeStandardOrUndefined()
+                || windowingMode == WINDOWING_MODE_FULLSCREEN
+                || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
+            return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
+        } else if (!getWindowConfiguration().persistTaskBounds()) {
+            return mStack.getRequestedOverrideBounds();
+        }
+        return mLastNonFullscreenBounds;
+    }
+
+    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
+        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
+            final ActivityRecord r = getChildAt(activityNdx);
+            if (r.visible) {
+                r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
+            }
+        }
+    }
+
+    void setRootProcess(WindowProcessController proc) {
+        clearRootProcess();
+        if (intent != null
+                && (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
+            mRootProcess = proc;
+            mRootProcess.addRecentTask(this);
+        }
+    }
+
+    void clearRootProcess() {
+        if (mRootProcess != null) {
+            mRootProcess.removeRecentTask(this);
+            mRootProcess = null;
+        }
+    }
+
+    void clearAllPendingOptions() {
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            getChildAt(i).clearOptionsLocked(false /* withAbort */);
+        }
     }
 
     @Override
@@ -145,8 +2234,8 @@
         return getTaskStack() != null ? getTaskStack().getDisplayContent() : null;
     }
 
-    TaskStack getTaskStack() {
-        return (TaskStack) getParent();
+    ActivityStack getTaskStack() {
+        return (ActivityStack) getParent();
     }
 
     int getAdjustedAddPosition(ActivityRecord r, int suggestedPosition) {
@@ -205,32 +2294,25 @@
     }
 
     @Override
-    void removeIfPossible() {
-        if (shouldDeferRemoval()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
-            return;
-        }
-        removeImmediately();
-    }
-
-    @Override
     void removeImmediately() {
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "removeTask");
         super.removeImmediately();
     }
 
-    // TODO: Consolidate this with TaskRecord.reparent()
-    void reparent(TaskStack stack, int position, boolean moveParents, String reason) {
+    // TODO: Consolidate this with Task.reparent()
+    void reparent(ActivityStack stack, int position, boolean moveParents, String reason) {
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + getTaskStack());
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
 
-        final ActivityStack prevStack = getTaskStack().mActivityStack;
+        final ActivityStack prevStack = getTaskStack();
         final boolean wasTopFocusedStack =
                 mAtmService.mRootActivityContainer.isTopDisplayFocusedStack(prevStack);
         final ActivityDisplay prevStackDisplay = prevStack.getDisplay();
 
+        position = stack.findPositionForTask(this, position, showForAllUsers());
+
         reparent(stack, position);
 
         if (!moveParents) {
@@ -238,8 +2320,7 @@
             prevStack.moveHomeStackToFrontIfNeeded(wasTopFocusedStack, prevStackDisplay, reason);
         }
 
-        // TODO(task-merge): Remove cast.
-        stack.positionChildAt(position, (TaskRecord) this, moveParents);
+        stack.positionChildAt(position, this, moveParents);
 
         // If we are moving from the fullscreen stack to the pinned stack then we want to preserve
         // our insets so that there will not be a jump in the area covered by system decorations.
@@ -247,12 +2328,6 @@
         mPreserveNonFloatingState = stack.inPinnedWindowingMode();
     }
 
-    /** @see ActivityTaskManagerService#positionTaskInStack(int, int, int). */
-    void positionAt(int position) {
-        // TODO(task-merge): Remove cast.
-        getTaskStack().positionChildAt(position, (TaskRecord) this, false /* includingParents */);
-    }
-
     void setSendingToBottom(boolean toBottom) {
         for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
             mChildren.get(appTokenNdx).sendingToBottom = toBottom;
@@ -747,7 +2822,7 @@
     }
 
     String getName() {
-        return toShortString();
+        return "Task=" + mTaskId;
     }
 
     void clearPreserveNonFloatingState() {
@@ -781,13 +2856,13 @@
 
         final long token = proto.start(fieldId);
         super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
-        proto.write(ID, mTaskId);
+        proto.write(TaskProto.ID, mTaskId);
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final ActivityRecord activity = mChildren.get(i);
             activity.writeToProto(proto, APP_WINDOW_TOKENS, logLevel);
         }
         proto.write(FILLS_PARENT, matchParentBounds());
-        getBounds().writeToProto(proto, BOUNDS);
+        getBounds().writeToProto(proto, TaskProto.BOUNDS);
         mOverrideDisplayedBounds.writeToProto(proto, DISPLAYED_BOUNDS);
         if (mSurfaceControl != null) {
             proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
@@ -816,7 +2891,609 @@
         }
     }
 
-    String toShortString() {
-        return "Task=" + mTaskId;
+    /**
+     * Fills in a {@link TaskInfo} with information from this task.
+     * @param info the {@link TaskInfo} to fill in
+     */
+    void fillTaskInfo(TaskInfo info) {
+        getNumRunningActivities(mReuseActivitiesReport);
+        info.userId = mUserId;
+        info.stackId = getStackId();
+        info.taskId = mTaskId;
+        info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
+        info.isRunning = getTopActivity() != null;
+        info.baseIntent = new Intent(getBaseIntent());
+        info.baseActivity = mReuseActivitiesReport.base != null
+                ? mReuseActivitiesReport.base.intent.getComponent()
+                : null;
+        info.topActivity = mReuseActivitiesReport.top != null
+                ? mReuseActivitiesReport.top.mActivityComponent
+                : null;
+        info.origActivity = origActivity;
+        info.realActivity = realActivity;
+        info.numActivities = mReuseActivitiesReport.numActivities;
+        info.lastActiveTime = lastActiveTime;
+        info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
+        info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
+        info.resizeMode = mResizeMode;
+        info.configuration.setTo(getConfiguration());
+    }
+
+    /**
+     * Returns a {@link TaskInfo} with information from this task.
+     */
+    ActivityManager.RunningTaskInfo getTaskInfo() {
+        ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
+        fillTaskInfo(info);
+        return info;
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("userId="); pw.print(mUserId);
+        pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
+        pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
+        pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
+        pw.print(" mCallingPackage="); pw.println(mCallingPackage);
+        if (affinity != null || rootAffinity != null) {
+            pw.print(prefix); pw.print("affinity="); pw.print(affinity);
+            if (affinity == null || !affinity.equals(rootAffinity)) {
+                pw.print(" root="); pw.println(rootAffinity);
+            } else {
+                pw.println();
+            }
+        }
+        if (voiceSession != null || voiceInteractor != null) {
+            pw.print(prefix); pw.print("VOICE: session=0x");
+            pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
+            pw.print(" interactor=0x");
+            pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
+        }
+        if (intent != null) {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append(prefix); sb.append("intent={");
+            intent.toShortString(sb, false, true, false, false);
+            sb.append('}');
+            pw.println(sb.toString());
+        }
+        if (affinityIntent != null) {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append(prefix); sb.append("affinityIntent={");
+            affinityIntent.toShortString(sb, false, true, false, false);
+            sb.append('}');
+            pw.println(sb.toString());
+        }
+        if (origActivity != null) {
+            pw.print(prefix); pw.print("origActivity=");
+            pw.println(origActivity.flattenToShortString());
+        }
+        if (realActivity != null) {
+            pw.print(prefix); pw.print("mActivityComponent=");
+            pw.println(realActivity.flattenToShortString());
+        }
+        if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) {
+            pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
+            pw.print(" isPersistable="); pw.print(isPersistable);
+            pw.print(" numFullscreen="); pw.print(numFullscreen);
+            pw.print(" activityType="); pw.println(getActivityType());
+        }
+        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
+                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
+            pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
+            pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
+            pw.print(" mReuseTask="); pw.print(mReuseTask);
+            pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
+        }
+        if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
+                || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
+                || mNextAffiliate != null) {
+            pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
+            pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
+            pw.print(" (");
+            if (mPrevAffiliate == null) {
+                pw.print("null");
+            } else {
+                pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
+            }
+            pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
+            pw.print(" (");
+            if (mNextAffiliate == null) {
+                pw.print("null");
+            } else {
+                pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
+            }
+            pw.println(")");
+        }
+        pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
+        if (!askedCompatMode || !inRecents || !isAvailable) {
+            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
+            pw.print(" inRecents="); pw.print(inRecents);
+            pw.print(" isAvailable="); pw.println(isAvailable);
+        }
+        if (lastDescription != null) {
+            pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
+        }
+        if (mRootProcess != null) {
+            pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
+        }
+        pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
+        pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
+        pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
+        pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
+        pw.print(" isResizeable=" + isResizeable());
+        pw.print(" lastActiveTime=" + lastActiveTime);
+        pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        if (stringName != null) {
+            sb.append(stringName);
+            sb.append(" U=");
+            sb.append(mUserId);
+            sb.append(" StackId=");
+            sb.append(getStackId());
+            sb.append(" sz=");
+            sb.append(getChildCount());
+            sb.append('}');
+            return sb.toString();
+        }
+        sb.append("Task{");
+        sb.append(Integer.toHexString(System.identityHashCode(this)));
+        sb.append(" #");
+        sb.append(mTaskId);
+        if (affinity != null) {
+            sb.append(" A=");
+            sb.append(affinity);
+        } else if (intent != null) {
+            sb.append(" I=");
+            sb.append(intent.getComponent().flattenToShortString());
+        } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
+            sb.append(" aI=");
+            sb.append(affinityIntent.getComponent().flattenToShortString());
+        } else {
+            sb.append(" ??");
+        }
+        stringName = sb.toString();
+        return toString();
+    }
+
+    @Override
+    public void writeToProto(ProtoOutputStream proto, long fieldId,
+            @WindowTraceLogLevel int logLevel) {
+        if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
+            return;
+        }
+
+        final long token = proto.start(fieldId);
+        writeToProtoInnerTaskOnly(proto, TASK, logLevel);
+        proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
+        for (int i = getChildCount() - 1; i >= 0; i--) {
+            final ActivityRecord activity = getChildAt(i);
+            activity.writeToProto(proto, ACTIVITIES);
+        }
+        proto.write(STACK_ID, getStackId());
+        if (mLastNonFullscreenBounds != null) {
+            mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
+        }
+        if (realActivity != null) {
+            proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
+        }
+        if (origActivity != null) {
+            proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
+        }
+        proto.write(ACTIVITY_TYPE, getActivityType());
+        proto.write(RESIZE_MODE, mResizeMode);
+        // TODO: Remove, no longer needed with windowingMode.
+        proto.write(FULLSCREEN, matchParentBounds());
+
+        if (!matchParentBounds()) {
+            final Rect bounds = getRequestedOverrideBounds();
+            bounds.writeToProto(proto, com.android.server.am.TaskRecordProto.BOUNDS);
+        }
+        proto.write(MIN_WIDTH, mMinWidth);
+        proto.write(MIN_HEIGHT, mMinHeight);
+        proto.end(token);
+    }
+
+    /** @see #getNumRunningActivities(TaskActivitiesReport) */
+    static class TaskActivitiesReport {
+        int numRunning;
+        int numActivities;
+        ActivityRecord top;
+        ActivityRecord base;
+
+        void reset() {
+            numRunning = numActivities = 0;
+            top = base = null;
+        }
+    }
+
+    /**
+     * Saves this {@link Task} to XML using given serializer.
+     */
+    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
+        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
+
+        out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
+        if (realActivity != null) {
+            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
+        }
+        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
+        if (origActivity != null) {
+            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
+        }
+        // Write affinity, and root affinity if it is different from affinity.
+        // We use the special string "@" for a null root affinity, so we can identify
+        // later whether we were given a root affinity or should just make it the
+        // same as the affinity.
+        if (affinity != null) {
+            out.attribute(null, ATTR_AFFINITY, affinity);
+            if (!affinity.equals(rootAffinity)) {
+                out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+            }
+        } else if (rootAffinity != null) {
+            out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
+        }
+        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
+        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
+        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
+        out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
+        out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
+        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
+        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
+        if (lastDescription != null) {
+            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
+        }
+        if (getTaskDescription() != null) {
+            getTaskDescription().saveToXml(out);
+        }
+        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
+        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
+        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
+        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
+        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
+        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
+        out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
+        out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
+                String.valueOf(mSupportsPictureInPicture));
+        if (mLastNonFullscreenBounds != null) {
+            out.attribute(
+                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
+        }
+        out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
+        out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
+        out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
+
+        if (affinityIntent != null) {
+            out.startTag(null, TAG_AFFINITYINTENT);
+            affinityIntent.saveToXml(out);
+            out.endTag(null, TAG_AFFINITYINTENT);
+        }
+
+        if (intent != null) {
+            out.startTag(null, TAG_INTENT);
+            intent.saveToXml(out);
+            out.endTag(null, TAG_INTENT);
+        }
+
+        final int numActivities = getChildCount();
+        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+            final ActivityRecord r = getChildAt(activityNdx);
+            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable()
+                    || ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
+                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT)
+                    && activityNdx > 0) {
+                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
+                break;
+            }
+            out.startTag(null, TAG_ACTIVITY);
+            r.saveToXml(out);
+            out.endTag(null, TAG_ACTIVITY);
+        }
+    }
+
+    @VisibleForTesting
+    static TaskFactory getTaskFactory() {
+        if (sTaskFactory == null) {
+            setTaskFactory(new TaskFactory());
+        }
+        return sTaskFactory;
+    }
+
+    static void setTaskFactory(TaskFactory factory) {
+        sTaskFactory = factory;
+    }
+
+    static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+            Intent intent, IVoiceInteractionSession voiceSession,
+            IVoiceInteractor voiceInteractor, ActivityStack stack) {
+        return getTaskFactory().create(
+                service, taskId, info, intent, voiceSession, voiceInteractor, stack);
+    }
+
+    static Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+            Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+        return getTaskFactory().create(service, taskId, info, intent, taskDescription, stack);
+    }
+
+    static Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+            throws IOException, XmlPullParserException {
+        return getTaskFactory().restoreFromXml(in, stackSupervisor);
+    }
+
+    /**
+     * A factory class used to create {@link Task} or its subclass if any. This can be
+     * specified when system boots by setting it with
+     * {@link #setTaskFactory(TaskFactory)}.
+     */
+    static class TaskFactory {
+
+        Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+                Intent intent, IVoiceInteractionSession voiceSession,
+                IVoiceInteractor voiceInteractor, ActivityStack stack) {
+            return new Task(service, taskId, info, intent, voiceSession, voiceInteractor,
+                    null /*taskDescription*/, stack);
+        }
+
+        Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+                Intent intent, TaskDescription taskDescription, ActivityStack stack) {
+            return new Task(service, taskId, info, intent, null /*voiceSession*/,
+                    null /*voiceInteractor*/, taskDescription, stack);
+        }
+
+        /**
+         * Should only be used when we're restoring {@link Task} from storage.
+         */
+        Task create(ActivityTaskManagerService service, int taskId, Intent intent,
+                Intent affinityIntent, String affinity, String rootAffinity,
+                ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
+                boolean autoRemoveRecents, boolean askedCompatMode, int userId,
+                int effectiveUid, String lastDescription,
+                long lastTimeMoved, boolean neverRelinquishIdentity,
+                TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
+                int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
+                int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
+                boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
+            return new Task(service, taskId, intent, affinityIntent, affinity,
+                    rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
+                    askedCompatMode, userId, effectiveUid, lastDescription,
+                    lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
+                    prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
+                    resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
+                    minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
+                    null /*_voiceInteractor*/, stack);
+        }
+
+        Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+                throws IOException, XmlPullParserException {
+            Intent intent = null;
+            Intent affinityIntent = null;
+            ArrayList<ActivityRecord> activities = new ArrayList<>();
+            ComponentName realActivity = null;
+            boolean realActivitySuspended = false;
+            ComponentName origActivity = null;
+            String affinity = null;
+            String rootAffinity = null;
+            boolean hasRootAffinity = false;
+            boolean rootHasReset = false;
+            boolean autoRemoveRecents = false;
+            boolean askedCompatMode = false;
+            int taskType = 0;
+            int userId = 0;
+            boolean userSetupComplete = true;
+            int effectiveUid = -1;
+            String lastDescription = null;
+            long lastTimeOnTop = 0;
+            boolean neverRelinquishIdentity = true;
+            int taskId = INVALID_TASK_ID;
+            final int outerDepth = in.getDepth();
+            TaskDescription taskDescription = new TaskDescription();
+            int taskAffiliation = INVALID_TASK_ID;
+            int taskAffiliationColor = 0;
+            int prevTaskId = INVALID_TASK_ID;
+            int nextTaskId = INVALID_TASK_ID;
+            int callingUid = -1;
+            String callingPackage = "";
+            int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
+            boolean supportsPictureInPicture = false;
+            Rect lastNonFullscreenBounds = null;
+            int minWidth = INVALID_MIN_SIZE;
+            int minHeight = INVALID_MIN_SIZE;
+            int persistTaskVersion = 0;
+
+            for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
+                final String attrName = in.getAttributeName(attrNdx);
+                final String attrValue = in.getAttributeValue(attrNdx);
+                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: attribute name="
+                        + attrName + " value=" + attrValue);
+                switch (attrName) {
+                    case ATTR_TASKID:
+                        if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_REALACTIVITY:
+                        realActivity = ComponentName.unflattenFromString(attrValue);
+                        break;
+                    case ATTR_REALACTIVITY_SUSPENDED:
+                        realActivitySuspended = Boolean.valueOf(attrValue);
+                        break;
+                    case ATTR_ORIGACTIVITY:
+                        origActivity = ComponentName.unflattenFromString(attrValue);
+                        break;
+                    case ATTR_AFFINITY:
+                        affinity = attrValue;
+                        break;
+                    case ATTR_ROOT_AFFINITY:
+                        rootAffinity = attrValue;
+                        hasRootAffinity = true;
+                        break;
+                    case ATTR_ROOTHASRESET:
+                        rootHasReset = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_AUTOREMOVERECENTS:
+                        autoRemoveRecents = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_ASKEDCOMPATMODE:
+                        askedCompatMode = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_USERID:
+                        userId = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_USER_SETUP_COMPLETE:
+                        userSetupComplete = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_EFFECTIVE_UID:
+                        effectiveUid = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_TASKTYPE:
+                        taskType = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_LASTDESCRIPTION:
+                        lastDescription = attrValue;
+                        break;
+                    case ATTR_LASTTIMEMOVED:
+                        lastTimeOnTop = Long.parseLong(attrValue);
+                        break;
+                    case ATTR_NEVERRELINQUISH:
+                        neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_TASK_AFFILIATION:
+                        taskAffiliation = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_PREV_AFFILIATION:
+                        prevTaskId = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_NEXT_AFFILIATION:
+                        nextTaskId = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_TASK_AFFILIATION_COLOR:
+                        taskAffiliationColor = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_CALLING_UID:
+                        callingUid = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_CALLING_PACKAGE:
+                        callingPackage = attrValue;
+                        break;
+                    case ATTR_RESIZE_MODE:
+                        resizeMode = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
+                        supportsPictureInPicture = Boolean.parseBoolean(attrValue);
+                        break;
+                    case ATTR_NON_FULLSCREEN_BOUNDS:
+                        lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
+                        break;
+                    case ATTR_MIN_WIDTH:
+                        minWidth = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_MIN_HEIGHT:
+                        minHeight = Integer.parseInt(attrValue);
+                        break;
+                    case ATTR_PERSIST_TASK_VERSION:
+                        persistTaskVersion = Integer.parseInt(attrValue);
+                        break;
+                    default:
+                        if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
+                            taskDescription.restoreFromXml(attrName, attrValue);
+                        } else {
+                            Slog.w(TAG, "Task: Unknown attribute=" + attrName);
+                        }
+                }
+            }
+
+            int event;
+            while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
+                    && (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
+                if (event == XmlPullParser.START_TAG) {
+                    final String name = in.getName();
+                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
+                            "Task: START_TAG name=" + name);
+                    if (TAG_AFFINITYINTENT.equals(name)) {
+                        affinityIntent = Intent.restoreFromXml(in);
+                    } else if (TAG_INTENT.equals(name)) {
+                        intent = Intent.restoreFromXml(in);
+                    } else if (TAG_ACTIVITY.equals(name)) {
+                        ActivityRecord activity =
+                                ActivityRecord.restoreFromXml(in, stackSupervisor);
+                        if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "Task: activity="
+                                + activity);
+                        if (activity != null) {
+                            activities.add(activity);
+                        }
+                    } else {
+                        handleUnknownTag(name, in);
+                    }
+                }
+            }
+            if (!hasRootAffinity) {
+                rootAffinity = affinity;
+            } else if ("@".equals(rootAffinity)) {
+                rootAffinity = null;
+            }
+            if (effectiveUid <= 0) {
+                Intent checkIntent = intent != null ? intent : affinityIntent;
+                effectiveUid = 0;
+                if (checkIntent != null) {
+                    IPackageManager pm = AppGlobals.getPackageManager();
+                    try {
+                        ApplicationInfo ai = pm.getApplicationInfo(
+                                checkIntent.getComponent().getPackageName(),
+                                PackageManager.MATCH_UNINSTALLED_PACKAGES
+                                        | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
+                        if (ai != null) {
+                            effectiveUid = ai.uid;
+                        }
+                    } catch (RemoteException e) {
+                    }
+                }
+                Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
+                        + ": effectiveUid=" + effectiveUid);
+            }
+
+            if (persistTaskVersion < 1) {
+                // We need to convert the resize mode of home activities saved before version one if
+                // they are marked as RESIZE_MODE_RESIZEABLE to
+                // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
+                // before version 1 and the system didn't resize home activities before then.
+                if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
+                    resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
+                }
+            } else {
+                // This activity has previously marked itself explicitly as both resizeable and
+                // supporting picture-in-picture.  Since there is no longer a requirement for
+                // picture-in-picture activities to be resizeable, we can mark this simply as
+                // resizeable and supporting picture-in-picture separately.
+                if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
+                    resizeMode = RESIZE_MODE_RESIZEABLE;
+                    supportsPictureInPicture = true;
+                }
+            }
+
+            final Task task = create(stackSupervisor.mService,
+                    taskId, intent, affinityIntent,
+                    affinity, rootAffinity, realActivity, origActivity, rootHasReset,
+                    autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
+                    lastTimeOnTop, neverRelinquishIdentity, taskDescription,
+                    taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
+                    callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
+                    userSetupComplete, minWidth, minHeight, null /*stack*/);
+            task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
+            task.setBounds(lastNonFullscreenBounds);
+
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                task.addChild(activities.get(activityNdx));
+            }
+
+            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
+            return task;
+        }
+
+        void handleUnknownTag(String name, XmlPullParser in)
+                throws IOException, XmlPullParserException {
+            Slog.e(TAG, "restoreTask: Unexpected name=" + name);
+            XmlUtils.skipCurrentTag(in);
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index a61c908..688fe12 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -350,7 +350,7 @@
     void notifyActivityPinned(ActivityRecord r) {
         mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
-                r.getTaskRecord().mTaskId, r.getStackId(), r.packageName);
+                r.getTask().mTaskId, r.getStackId(), r.packageName);
         msg.sendingUid = r.mUserId;
         forAllLocalListeners(mNotifyActivityPinned, msg);
         msg.sendToTarget();
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 31145de..d7bc072 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -93,7 +93,7 @@
     }
 
     @VisibleForTesting
-    int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout, ActivityRecord activity,
+    int onCalculate(Task task, ActivityInfo.WindowLayout layout, ActivityRecord activity,
             ActivityRecord source, ActivityOptions options, LaunchParams currentParams,
             LaunchParams outParams) {
         return onCalculate(task, layout, activity, source, options, PHASE_BOUNDS, currentParams,
@@ -101,7 +101,7 @@
     }
 
     @Override
-    public int onCalculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+    public int onCalculate(Task task, ActivityInfo.WindowLayout layout,
                            ActivityRecord activity, ActivityRecord source, ActivityOptions options,
                            int phase, LaunchParams currentParams, LaunchParams outParams) {
         initLogBuilder(task, activity);
@@ -111,7 +111,7 @@
         return result;
     }
 
-    private int calculate(TaskRecord task, ActivityInfo.WindowLayout layout,
+    private int calculate(Task task, ActivityInfo.WindowLayout layout,
             ActivityRecord activity, ActivityRecord source, ActivityOptions options, int phase,
             LaunchParams currentParams, LaunchParams outParams) {
         final ActivityRecord root;
@@ -292,7 +292,7 @@
         return RESULT_CONTINUE;
     }
 
-    private int getPreferredLaunchDisplay(@Nullable TaskRecord task,
+    private int getPreferredLaunchDisplay(@Nullable Task task,
             @Nullable ActivityOptions options, ActivityRecord source, LaunchParams currentParams) {
         if (!mSupervisor.mService.mSupportsMultiDisplay) {
             return DEFAULT_DISPLAY;
@@ -865,7 +865,7 @@
         inOutBounds.offset(horizontalOffset, verticalOffset);
     }
 
-    private void initLogBuilder(TaskRecord task, ActivityRecord activity) {
+    private void initLogBuilder(Task task, ActivityRecord activity) {
         if (DEBUG) {
             mLogBuilder = new StringBuilder("TaskLaunchParamsModifier:task=" + task
                     + " activity=" + activity);
diff --git a/services/core/java/com/android/server/wm/TaskPersister.java b/services/core/java/com/android/server/wm/TaskPersister.java
index f9a75d3..1e2f0d0 100644
--- a/services/core/java/com/android/server/wm/TaskPersister.java
+++ b/services/core/java/com/android/server/wm/TaskPersister.java
@@ -118,7 +118,7 @@
         mPersisterQueue.addListener(this);
     }
 
-    private void removeThumbnails(TaskRecord task) {
+    private void removeThumbnails(Task task) {
         mPersisterQueue.removeItems(
                 item -> {
                     File file = new File(item.mFilePath);
@@ -185,7 +185,7 @@
         mTaskIdsInFile.delete(userId);
     }
 
-    void wakeup(TaskRecord task, boolean flush) {
+    void wakeup(Task task, boolean flush) {
         synchronized (mPersisterQueue) {
             if (task != null) {
                 final TaskWriteQueueItem item = mPersisterQueue.findLastItem(
@@ -256,12 +256,12 @@
         }
     }
 
-    private TaskRecord taskIdToTask(int taskId, ArrayList<TaskRecord> tasks) {
+    private Task taskIdToTask(int taskId, ArrayList<Task> tasks) {
         if (taskId < 0) {
             return null;
         }
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = tasks.get(taskNdx);
+            final Task task = tasks.get(taskNdx);
             if (task.mTaskId == taskId) {
                 return task;
             }
@@ -270,8 +270,8 @@
         return null;
     }
 
-    List<TaskRecord> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
-        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
+    List<Task> restoreTasksForUserLocked(final int userId, SparseBooleanArray preaddedTasks) {
+        final ArrayList<Task> tasks = new ArrayList<Task>();
         ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
 
         File userTasksDir = getUserTasksDir(userId);
@@ -320,7 +320,7 @@
                     if (event == XmlPullParser.START_TAG) {
                         if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: START_TAG name=" + name);
                         if (TAG_TASK.equals(name)) {
-                            final TaskRecord task = TaskRecord.restoreFromXml(in, mStackSupervisor);
+                            final Task task = Task.restoreFromXml(in, mStackSupervisor);
                             if (DEBUG) Slog.d(TAG, "restoreTasksForUserLocked: restored task="
                                     + task);
                             if (task != null) {
@@ -375,14 +375,14 @@
 
         // Fix up task affiliation from taskIds
         for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            final TaskRecord task = tasks.get(taskNdx);
+            final Task task = tasks.get(taskNdx);
             task.setPrevAffiliate(taskIdToTask(task.mPrevAffiliateTaskId, tasks));
             task.setNextAffiliate(taskIdToTask(task.mNextAffiliateTaskId, tasks));
         }
 
-        Collections.sort(tasks, new Comparator<TaskRecord>() {
+        Collections.sort(tasks, new Comparator<Task>() {
             @Override
-            public int compare(TaskRecord lhs, TaskRecord rhs) {
+            public int compare(Task lhs, Task rhs) {
                 final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
                 if (diff < 0) {
                     return -1;
@@ -507,14 +507,14 @@
 
     private static class TaskWriteQueueItem implements PersisterQueue.WriteQueueItem {
         private final ActivityTaskManagerService mService;
-        private final TaskRecord mTask;
+        private final Task mTask;
 
-        TaskWriteQueueItem(TaskRecord task, ActivityTaskManagerService service) {
+        TaskWriteQueueItem(Task task, ActivityTaskManagerService service) {
             mTask = task;
             mService = service;
         }
 
-        private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
+        private StringWriter saveToXml(Task task) throws IOException, XmlPullParserException {
             if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
             final XmlSerializer xmlSerializer = new FastXmlSerializer();
             StringWriter stringWriter = new StringWriter();
@@ -542,7 +542,7 @@
         public void process() {
             // Write out one task.
             StringWriter stringWriter = null;
-            TaskRecord task = mTask;
+            Task task = mTask;
             if (DEBUG) Slog.d(TAG, "Writing task=" + task);
             synchronized (mService.mGlobalLock) {
                 if (task.inRecents) {
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
deleted file mode 100644
index 2975d0a..0000000
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ /dev/null
@@ -1,2776 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
-import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.ActivityTaskManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
-import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
-import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
-import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
-import static android.view.Display.DEFAULT_DISPLAY;
-
-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;
-import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
-import static com.android.server.am.TaskRecordProto.STACK_ID;
-import static com.android.server.am.TaskRecordProto.TASK;
-import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED;
-import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
-import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-import static com.android.server.wm.ActivityStackSupervisor.REMOVE_FROM_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
-import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-
-import static java.lang.Integer.MAX_VALUE;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
-import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityManager.TaskSnapshot;
-import android.app.ActivityOptions;
-import android.app.ActivityTaskManager;
-import android.app.AppGlobals;
-import android.app.TaskInfo;
-import android.app.WindowConfiguration;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.graphics.Rect;
-import android.os.Debug;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.Trace;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.service.voice.IVoiceInteractionSession;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.Display;
-import android.view.DisplayInfo;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.util.XmlUtils;
-import com.android.server.protolog.common.ProtoLog;
-import com.android.server.wm.ActivityStack.ActivityState;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Objects;
-
-class TaskRecord extends Task {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_ATM;
-    private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
-    private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
-    private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK;
-    private static final String TAG_TASKS = TAG + POSTFIX_TASKS;
-
-    private static final String ATTR_TASKID = "task_id";
-    private static final String TAG_INTENT = "intent";
-    private static final String TAG_AFFINITYINTENT = "affinity_intent";
-    private static final String ATTR_REALACTIVITY = "real_activity";
-    private static final String ATTR_REALACTIVITY_SUSPENDED = "real_activity_suspended";
-    private static final String ATTR_ORIGACTIVITY = "orig_activity";
-    private static final String TAG_ACTIVITY = "activity";
-    private static final String ATTR_AFFINITY = "affinity";
-    private static final String ATTR_ROOT_AFFINITY = "root_affinity";
-    private static final String ATTR_ROOTHASRESET = "root_has_reset";
-    private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
-    private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
-    private static final String ATTR_USERID = "user_id";
-    private static final String ATTR_USER_SETUP_COMPLETE = "user_setup_complete";
-    private static final String ATTR_EFFECTIVE_UID = "effective_uid";
-    @Deprecated
-    private static final String ATTR_TASKTYPE = "task_type";
-    private static final String ATTR_LASTDESCRIPTION = "last_description";
-    private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
-    private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
-    private static final String ATTR_TASK_AFFILIATION = "task_affiliation";
-    private static final String ATTR_PREV_AFFILIATION = "prev_affiliation";
-    private static final String ATTR_NEXT_AFFILIATION = "next_affiliation";
-    private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color";
-    private static final String ATTR_CALLING_UID = "calling_uid";
-    private static final String ATTR_CALLING_PACKAGE = "calling_package";
-    private static final String ATTR_SUPPORTS_PICTURE_IN_PICTURE = "supports_picture_in_picture";
-    private static final String ATTR_RESIZE_MODE = "resize_mode";
-    private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds";
-    private static final String ATTR_MIN_WIDTH = "min_width";
-    private static final String ATTR_MIN_HEIGHT = "min_height";
-    private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
-
-    // Current version of the task record we persist. Used to check if we need to run any upgrade
-    // code.
-    private static final int PERSIST_TASK_VERSION = 1;
-
-    private static final int INVALID_MIN_SIZE = -1;
-
-    /**
-     * The modes to control how the stack is moved to the front when calling
-     * {@link TaskRecord#reparent}.
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            REPARENT_MOVE_STACK_TO_FRONT,
-            REPARENT_KEEP_STACK_AT_FRONT,
-            REPARENT_LEAVE_STACK_IN_PLACE
-    })
-    @interface ReparentMoveStackMode {}
-    // Moves the stack to the front if it was not at the front
-    static final int REPARENT_MOVE_STACK_TO_FRONT = 0;
-    // Only moves the stack to the front if it was focused or front most already
-    static final int REPARENT_KEEP_STACK_AT_FRONT = 1;
-    // Do not move the stack as a part of reparenting
-    static final int REPARENT_LEAVE_STACK_IN_PLACE = 2;
-
-    /**
-     * The factory used to create {@link TaskRecord}. This allows OEM subclass {@link TaskRecord}.
-     */
-    private static TaskRecordFactory sTaskRecordFactory;
-
-    String affinity;        // The affinity name for this task, or null; may change identity.
-    String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
-    final IVoiceInteractionSession voiceSession;    // Voice interaction session driving task
-    final IVoiceInteractor voiceInteractor;         // Associated interactor to provide to app
-    Intent intent;          // The original intent that started the task. Note that this value can
-                            // be null.
-    Intent affinityIntent;  // Intent of affinity-moved activity that started this task.
-    int effectiveUid;       // The current effective uid of the identity of this task.
-    ComponentName origActivity; // The non-alias activity component of the intent.
-    ComponentName realActivity; // The actual activity component that started the task.
-    boolean realActivitySuspended; // True if the actual activity component that started the
-                                   // task is suspended.
-    boolean inRecents;      // Actually in the recents list?
-    long lastActiveTime;    // Last time this task was active in the current device session,
-                            // including sleep. This time is initialized to the elapsed time when
-                            // restored from disk.
-    boolean isAvailable;    // Is the activity available to be launched?
-    boolean rootWasReset;   // True if the intent at the root of the task had
-                            // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
-    boolean autoRemoveRecents;  // If true, we should automatically remove the task from
-                                // recents when activity finishes
-    boolean askedCompatMode;// Have asked the user about compat mode for this task.
-    boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
-
-    String stringName;      // caching of toString() result.
-    boolean mUserSetupComplete; // The user set-up is complete as of the last time the task activity
-                                // was changed.
-
-    int numFullscreen;      // Number of fullscreen activities.
-
-    /** Can't be put in lockTask mode. */
-    final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
-    /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
-    final static int LOCK_TASK_AUTH_PINNABLE = 1;
-    /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
-    final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
-    /** Can enter lockTask without user approval. Can start over existing lockTask task. */
-    final static int LOCK_TASK_AUTH_WHITELISTED = 3;
-    /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
-     * lockTask task. */
-    final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
-    int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
-
-    int mLockTaskUid = -1;  // The uid of the application that called startLockTask().
-
-    /** Current stack. Setter must always be used to update the value. */
-    private ActivityStack mStack;
-
-    /** The process that had previously hosted the root activity of this task.
-     * Used to know that we should try harder to keep this process around, in case the
-     * user wants to return to it. */
-    private WindowProcessController mRootProcess;
-
-    /** Takes on same value as first root activity */
-    boolean isPersistable = false;
-    int maxRecents;
-
-    /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for
-     * determining the order when restoring. Sign indicates whether last task movement was to front
-     * (positive) or back (negative). Absolute value indicates time. */
-    long mLastTimeMoved;
-
-    /** If original intent did not allow relinquishing task identity, save that information */
-    private boolean mNeverRelinquishIdentity = true;
-
-    // Used in the unique case where we are clearing the task in order to reuse it. In that case we
-    // do not want to delete the stack when the task goes empty.
-    private boolean mReuseTask = false;
-
-    CharSequence lastDescription; // Last description captured for this item.
-
-    int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent.
-    int mAffiliatedTaskColor; // color of the parent task affiliation.
-    TaskRecord mPrevAffiliate; // previous task in affiliated chain.
-    int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence.
-    TaskRecord mNextAffiliate; // next task in affiliated chain.
-    int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence.
-
-    // For relaunching the task from recents as though it was launched by the original launcher.
-    int mCallingUid;
-    String mCallingPackage;
-
-    private final Rect mTmpStableBounds = new Rect();
-    private final Rect mTmpNonDecorBounds = new Rect();
-    private final Rect mTmpBounds = new Rect();
-    private final Rect mTmpInsets = new Rect();
-
-    // Last non-fullscreen bounds the task was launched in or resized to.
-    // The information is persisted and used to determine the appropriate stack to launch the
-    // task into on restore.
-    Rect mLastNonFullscreenBounds = null;
-    // Minimal width and height of this task when it's resizeable. -1 means it should use the
-    // default minimal width/height.
-    int mMinWidth;
-    int mMinHeight;
-
-    // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible)
-    // This number will be assigned when we evaluate OOM scores for all visible tasks.
-    int mLayerRank = -1;
-
-    /** Helper object used for updating override configuration. */
-    private Configuration mTmpConfig = new Configuration();
-
-    /** Used by fillTaskInfo */
-    final TaskActivitiesReport mReuseActivitiesReport = new TaskActivitiesReport();
-
-    /**
-     * Don't use constructor directly. Use {@link #create(ActivityTaskManagerService, int,
-     * ActivityInfo, Intent, TaskDescription)} instead.
-     */
-    TaskRecord(ActivityTaskManagerService atmService, int _taskId, ActivityInfo info, Intent _intent,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
-            TaskDescription _taskDescription, ActivityStack stack) {
-        this(atmService, _taskId, _intent,  null /*_affinityIntent*/, null /*_affinity*/,
-                null /*_rootAffinity*/, null /*_realActivity*/, null /*_origActivity*/,
-                false /*_rootWasReset*/, false /*_autoRemoveRecents*/, false /*_askedCompatMode*/,
-                UserHandle.getUserId(info.applicationInfo.uid), 0 /*_effectiveUid*/,
-                null /*_lastDescription*/, System.currentTimeMillis(),
-                true /*neverRelinquishIdentity*/,
-                _taskDescription != null ? _taskDescription : new TaskDescription(),
-                _taskId, INVALID_TASK_ID, INVALID_TASK_ID, 0 /*taskAffiliationColor*/,
-                info.applicationInfo.uid, info.packageName, info.resizeMode,
-                info.supportsPictureInPicture(), false /*_realActivitySuspended*/,
-                false /*userSetupComplete*/, INVALID_MIN_SIZE, INVALID_MIN_SIZE, info,
-                _voiceSession, _voiceInteractor, stack);
-    }
-
-    /** Don't use constructor directly. This is only used by XML parser. */
-    TaskRecord(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
-            Intent _affinityIntent, String _affinity, String _rootAffinity,
-            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
-            boolean _autoRemoveRecents, boolean _askedCompatMode, int _userId,
-            int _effectiveUid, String _lastDescription,
-            long lastTimeMoved, boolean neverRelinquishIdentity,
-            TaskDescription _lastTaskDescription, int taskAffiliation, int prevTaskId,
-            int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
-            int resizeMode, boolean supportsPictureInPicture, boolean _realActivitySuspended,
-            boolean userSetupComplete, int minWidth, int minHeight, ActivityInfo info,
-            IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor,
-            ActivityStack stack) {
-        super(_taskId, stack != null ? stack.mTaskStack : null, _userId, resizeMode,
-                supportsPictureInPicture, _lastTaskDescription, atmService);
-        mRemoteToken = new RemoteToken(this);
-        affinityIntent = _affinityIntent;
-        affinity = _affinity;
-        rootAffinity = _rootAffinity;
-        voiceSession = _voiceSession;
-        voiceInteractor = _voiceInteractor;
-        realActivity = _realActivity;
-        realActivitySuspended = _realActivitySuspended;
-        origActivity = _origActivity;
-        rootWasReset = _rootWasReset;
-        isAvailable = true;
-        autoRemoveRecents = _autoRemoveRecents;
-        askedCompatMode = _askedCompatMode;
-        mUserSetupComplete = userSetupComplete;
-        effectiveUid = _effectiveUid;
-        touchActiveTime();
-        lastDescription = _lastDescription;
-        mLastTimeMoved = lastTimeMoved;
-        mNeverRelinquishIdentity = neverRelinquishIdentity;
-        mAffiliatedTaskId = taskAffiliation;
-        mAffiliatedTaskColor = taskAffiliationColor;
-        mPrevAffiliateTaskId = prevTaskId;
-        mNextAffiliateTaskId = nextTaskId;
-        mCallingUid = callingUid;
-        mCallingPackage = callingPackage;
-        mResizeMode = resizeMode;
-        if (info != null) {
-            setIntent(_intent, info);
-            setMinDimensions(info);
-        } else {
-            intent = _intent;
-            mMinWidth = minWidth;
-            mMinHeight = minHeight;
-        }
-        mAtmService.getTaskChangeNotificationController().notifyTaskCreated(_taskId, realActivity);
-    }
-
-    void cleanUpResourcesForDestroy() {
-        if (hasChild()) {
-            return;
-        }
-
-        // This task is going away, so save the last state if necessary.
-        saveLaunchingStateIfNeeded();
-
-        // TODO: VI what about activity?
-        final boolean isVoiceSession = voiceSession != null;
-        if (isVoiceSession) {
-            try {
-                voiceSession.taskFinished(intent, mTaskId);
-            } catch (RemoteException e) {
-            }
-        }
-        if (autoRemoveFromRecents() || isVoiceSession) {
-            // Task creator asked to remove this when done, or this task was a voice
-            // interaction, so it should not remain on the recent tasks list.
-            mAtmService.mStackSupervisor.mRecentTasks.remove(this);
-        }
-
-        removeIfPossible();
-    }
-
-    @VisibleForTesting
-    @Override
-    void removeIfPossible() {
-        mAtmService.getLockTaskController().clearLockedTask(this);
-        super.removeIfPossible();
-        mAtmService.getTaskChangeNotificationController().notifyTaskRemoved(mTaskId);
-    }
-
-    void setResizeMode(int resizeMode) {
-        if (mResizeMode == resizeMode) {
-            return;
-        }
-        mResizeMode = resizeMode;
-        mAtmService.mRootActivityContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS);
-        mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
-        updateTaskDescription();
-    }
-
-    boolean resize(Rect bounds, int resizeMode, boolean preserveWindow, boolean deferResume) {
-        mAtmService.deferWindowLayout();
-
-        try {
-            final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0;
-
-            if (getParent() == null) {
-                // Task doesn't exist in window manager yet (e.g. was restored from recents).
-                // All we can do for now is update the bounds so it can be used when the task is
-                // added to window manager.
-                setBounds(bounds);
-                if (!inFreeformWindowingMode()) {
-                    // re-restore the task so it can have the proper stack association.
-                    mAtmService.mStackSupervisor.restoreRecentTaskLocked(this, null, !ON_TOP);
-                }
-                return true;
-            }
-
-            if (!canResizeToBounds(bounds)) {
-                throw new IllegalArgumentException("resizeTask: Can not resize task=" + this
-                        + " to bounds=" + bounds + " resizeMode=" + mResizeMode);
-            }
-
-            // Do not move the task to another stack here.
-            // This method assumes that the task is already placed in the right stack.
-            // we do not mess with that decision and we only do the resize!
-
-            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "resizeTask_" + mTaskId);
-
-            boolean updatedConfig = false;
-            mTmpConfig.setTo(getResolvedOverrideConfiguration());
-            if (setBounds(bounds) != BOUNDS_CHANGE_NONE) {
-                updatedConfig = !mTmpConfig.equals(getResolvedOverrideConfiguration());
-            }
-            // This variable holds information whether the configuration didn't change in a significant
-
-            // way and the activity was kept the way it was. If it's false, it means the activity
-            // had
-            // to be relaunched due to configuration change.
-            boolean kept = true;
-            if (updatedConfig) {
-                final ActivityRecord r = topRunningActivityLocked();
-                if (r != null && !deferResume) {
-                    kept = r.ensureActivityConfiguration(0 /* globalChanges */,
-                            preserveWindow);
-                    // Preserve other windows for resizing because if resizing happens when there
-                    // is a dialog activity in the front, the activity that still shows some
-                    // content to the user will become black and cause flickers. Note in most cases
-                    // this won't cause tons of irrelevant windows being preserved because only
-                    // activities in this task may experience a bounds change. Configs for other
-                    // activities stay the same.
-                    mAtmService.mRootActivityContainer.ensureActivitiesVisible(r, 0, preserveWindow);
-                    if (!kept) {
-                        mAtmService.mRootActivityContainer.resumeFocusedStacksTopActivities();
-                    }
-                }
-            }
-            resize(kept, forced);
-
-            saveLaunchingStateIfNeeded();
-
-            Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-            return kept;
-        } finally {
-            mAtmService.continueWindowLayout();
-        }
-    }
-
-    /**
-     * Convenience method to reparent a task to the top or bottom position of the stack.
-     */
-    boolean reparent(ActivityStack preferredStack, boolean toTop,
-            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
-            String reason) {
-        return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate, deferResume,
-                true /* schedulePictureInPictureModeChange */, reason);
-    }
-
-    /**
-     * Convenience method to reparent a task to the top or bottom position of the stack, with
-     * an option to skip scheduling the picture-in-picture mode change.
-     */
-    boolean reparent(ActivityStack preferredStack, boolean toTop,
-            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
-            boolean schedulePictureInPictureModeChange, String reason) {
-        return reparent(preferredStack, toTop ? MAX_VALUE : 0, moveStackMode, animate,
-                deferResume, schedulePictureInPictureModeChange, reason);
-    }
-
-    /** Convenience method to reparent a task to a specific position of the stack. */
-    boolean reparent(ActivityStack preferredStack, int position,
-            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
-            String reason) {
-        return reparent(preferredStack, position, moveStackMode, animate, deferResume,
-                true /* schedulePictureInPictureModeChange */, reason);
-    }
-
-    /**
-     * Reparents the task into a preferred stack, creating it if necessary.
-     *
-     * @param preferredStack the target stack to move this task
-     * @param position the position to place this task in the new stack
-     * @param animate whether or not we should wait for the new window created as a part of the
-     *            reparenting to be drawn and animated in
-     * @param moveStackMode whether or not to move the stack to the front always, only if it was
-     *            previously focused & in front, or never
-     * @param deferResume whether or not to update the visibility of other tasks and stacks that may
-     *            have changed as a result of this reparenting
-     * @param schedulePictureInPictureModeChange specifies whether or not to schedule the PiP mode
-     *            change. Callers may set this to false if they are explicitly scheduling PiP mode
-     *            changes themselves, like during the PiP animation
-     * @param reason the caller of this reparenting
-     * @return whether the task was reparented
-     */
-    // TODO: Inspect all call sites and change to just changing windowing mode of the stack vs.
-    // re-parenting the task. Can only be done when we are no longer using static stack Ids.
-    boolean reparent(ActivityStack preferredStack, int position,
-            @ReparentMoveStackMode int moveStackMode, boolean animate, boolean deferResume,
-            boolean schedulePictureInPictureModeChange, String reason) {
-        final ActivityStackSupervisor supervisor = mAtmService.mStackSupervisor;
-        final RootActivityContainer root = mAtmService.mRootActivityContainer;
-        final WindowManagerService windowManager = mAtmService.mWindowManager;
-        final ActivityStack sourceStack = getStack();
-        final ActivityStack toStack = supervisor.getReparentTargetStack(this, preferredStack,
-                position == MAX_VALUE);
-        if (toStack == sourceStack) {
-            return false;
-        }
-        if (!canBeLaunchedOnDisplay(toStack.mDisplayId)) {
-            return false;
-        }
-
-        final boolean toTopOfStack = position == MAX_VALUE;
-        if (toTopOfStack && toStack.getResumedActivity() != null
-                && toStack.topRunningActivityLocked() != null) {
-            // Pause the resumed activity on the target stack while re-parenting task on top of it.
-            toStack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */,
-                    null /* resuming */);
-        }
-
-        final int toStackWindowingMode = toStack.getWindowingMode();
-        final ActivityRecord topActivity = getTopActivity();
-
-        final boolean mightReplaceWindow = topActivity != null
-                && replaceWindowsOnTaskMove(getWindowingMode(), toStackWindowingMode);
-        if (mightReplaceWindow) {
-            // We are about to relaunch the activity because its configuration changed due to
-            // being maximized, i.e. size change. The activity will first remove the old window
-            // and then add a new one. This call will tell window manager about this, so it can
-            // preserve the old window until the new one is drawn. This prevents having a gap
-            // between the removal and addition, in which no window is visible. We also want the
-            // entrance of the new window to be properly animated.
-            // Note here we always set the replacing window first, as the flags might be needed
-            // during the relaunch. If we end up not doing any relaunch, we clear the flags later.
-            windowManager.setWillReplaceWindow(topActivity.appToken, animate);
-        }
-
-        mAtmService.deferWindowLayout();
-        boolean kept = true;
-        try {
-            final ActivityRecord r = topRunningActivityLocked();
-            final boolean wasFocused = r != null && root.isTopDisplayFocusedStack(sourceStack)
-                    && (topRunningActivityLocked() == r);
-            final boolean wasResumed = r != null && sourceStack.getResumedActivity() == r;
-            final boolean wasPaused = r != null && sourceStack.mPausingActivity == r;
-
-            // In some cases the focused stack isn't the front stack. E.g. pinned stack.
-            // Whenever we are moving the top activity from the front stack we want to make sure to
-            // move the stack to the front.
-            final boolean wasFront = r != null && sourceStack.isTopStackOnDisplay()
-                    && (sourceStack.topRunningActivityLocked() == r);
-
-            // Adjust the position for the new parent stack as needed.
-            position = toStack.getAdjustedPositionForTask(this, position, null /* starting */);
-
-            final boolean moveStackToFront = moveStackMode == REPARENT_MOVE_STACK_TO_FRONT
-                    || (moveStackMode == REPARENT_KEEP_STACK_AT_FRONT && (wasFocused || wasFront));
-
-            reparent(toStack.getTaskStack(), position, moveStackToFront, reason);
-
-            if (schedulePictureInPictureModeChange) {
-                // Notify of picture-in-picture mode changes
-                supervisor.scheduleUpdatePictureInPictureModeIfNeeded(this, sourceStack);
-            }
-
-            // If the task had focus before (or we're requested to move focus), move focus to the
-            // new stack by moving the stack to the front.
-            if (r != null) {
-                toStack.moveToFrontAndResumeStateIfNeeded(r, moveStackToFront, wasResumed,
-                        wasPaused, reason);
-            }
-            if (!animate) {
-                mAtmService.mStackSupervisor.mNoAnimActivities.add(topActivity);
-            }
-
-            // We might trigger a configuration change. Save the current task bounds for freezing.
-            // TODO: Should this call be moved inside the resize method in WM?
-            toStack.prepareFreezingTaskBounds();
-
-            // Make sure the task has the appropriate bounds/size for the stack it is in.
-            final boolean toStackSplitScreenPrimary =
-                    toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-            final Rect configBounds = getRequestedOverrideBounds();
-            if ((toStackWindowingMode == WINDOWING_MODE_FULLSCREEN
-                    || toStackWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY)
-                    && !Objects.equals(configBounds, toStack.getRequestedOverrideBounds())) {
-                kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
-            } else if (toStackWindowingMode == WINDOWING_MODE_FREEFORM) {
-                Rect bounds = getLaunchBounds();
-                if (bounds == null) {
-                    mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
-                    bounds = configBounds;
-                }
-                kept = resize(bounds, RESIZE_MODE_FORCED, !mightReplaceWindow, deferResume);
-            } else if (toStackSplitScreenPrimary || toStackWindowingMode == WINDOWING_MODE_PINNED) {
-                if (toStackSplitScreenPrimary && moveStackMode == REPARENT_KEEP_STACK_AT_FRONT) {
-                    // Move recents to front so it is not behind home stack when going into docked
-                    // mode
-                    mAtmService.mStackSupervisor.moveRecentsStackToFront(reason);
-                }
-                kept = resize(toStack.getRequestedOverrideBounds(), RESIZE_MODE_SYSTEM,
-                        !mightReplaceWindow, deferResume);
-            }
-        } finally {
-            mAtmService.continueWindowLayout();
-        }
-
-        if (mightReplaceWindow) {
-            // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old
-            // window), we need to clear the replace window settings. Otherwise, we schedule a
-            // timeout to remove the old window if the replacing window is not coming in time.
-            windowManager.scheduleClearWillReplaceWindows(topActivity.appToken, !kept);
-        }
-
-        if (!deferResume) {
-            // The task might have already been running and its visibility needs to be synchronized
-            // with the visibility of the stack / windows.
-            root.ensureActivitiesVisible(null, 0, !mightReplaceWindow);
-            root.resumeFocusedStacksTopActivities();
-        }
-
-        // TODO: Handle incorrect request to move before the actual move, not after.
-        supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(),
-                DEFAULT_DISPLAY, toStack);
-
-        return (preferredStack == toStack);
-    }
-
-    /**
-     * @return True if the windows of tasks being moved to the target stack from the source stack
-     * should be replaced, meaning that window manager will keep the old window around until the new
-     * is ready.
-     */
-    private static boolean replaceWindowsOnTaskMove(
-            int sourceWindowingMode, int targetWindowingMode) {
-        return sourceWindowingMode == WINDOWING_MODE_FREEFORM
-                || targetWindowingMode == WINDOWING_MODE_FREEFORM;
-    }
-
-    /**
-     * DO NOT HOLD THE ACTIVITY MANAGER LOCK WHEN CALLING THIS METHOD!
-     */
-    TaskSnapshot getSnapshot(boolean reducedResolution, boolean restoreFromDisk) {
-
-        // TODO: Move this to {@link TaskWindowContainerController} once recent tasks are more
-        // synchronized between AM and WM.
-        return mAtmService.mWindowManager.getTaskSnapshot(mTaskId, mUserId, reducedResolution,
-                restoreFromDisk);
-    }
-
-    void touchActiveTime() {
-        lastActiveTime = SystemClock.elapsedRealtime();
-    }
-
-    long getInactiveDuration() {
-        return SystemClock.elapsedRealtime() - lastActiveTime;
-    }
-
-    /** Sets the original intent, and the calling uid and package. */
-    void setIntent(ActivityRecord r) {
-        mCallingUid = r.launchedFromUid;
-        mCallingPackage = r.launchedFromPackage;
-        setIntent(r.intent, r.info);
-        setLockTaskAuth(r);
-    }
-
-    /** Sets the original intent, _without_ updating the calling uid or package. */
-    private void setIntent(Intent _intent, ActivityInfo info) {
-        if (intent == null) {
-            mNeverRelinquishIdentity =
-                    (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0;
-        } else if (mNeverRelinquishIdentity) {
-            return;
-        }
-
-        affinity = info.taskAffinity;
-        if (intent == null) {
-            // If this task already has an intent associated with it, don't set the root
-            // affinity -- we don't want it changing after initially set, but the initially
-            // set value may be null.
-            rootAffinity = affinity;
-        }
-        effectiveUid = info.applicationInfo.uid;
-        stringName = null;
-
-        if (info.targetActivity == null) {
-            if (_intent != null) {
-                // If this Intent has a selector, we want to clear it for the
-                // recent task since it is not relevant if the user later wants
-                // to re-launch the app.
-                if (_intent.getSelector() != null || _intent.getSourceBounds() != null) {
-                    _intent = new Intent(_intent);
-                    _intent.setSelector(null);
-                    _intent.setSourceBounds(null);
-                }
-            }
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent);
-            intent = _intent;
-            realActivity = _intent != null ? _intent.getComponent() : null;
-            origActivity = null;
-        } else {
-            ComponentName targetComponent = new ComponentName(
-                    info.packageName, info.targetActivity);
-            if (_intent != null) {
-                Intent targetIntent = new Intent(_intent);
-                targetIntent.setSelector(null);
-                targetIntent.setSourceBounds(null);
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                        "Setting Intent of " + this + " to target " + targetIntent);
-                intent = targetIntent;
-                realActivity = targetComponent;
-                origActivity = _intent.getComponent();
-            } else {
-                intent = null;
-                realActivity = targetComponent;
-                origActivity = new ComponentName(info.packageName, info.name);
-            }
-        }
-
-        final int intentFlags = intent == null ? 0 : intent.getFlags();
-        if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-            // Once we are set to an Intent with this flag, we count this
-            // task as having a true root activity.
-            rootWasReset = true;
-        }
-        mUserId = UserHandle.getUserId(info.applicationInfo.uid);
-        mUserSetupComplete = Settings.Secure.getIntForUser(
-                mAtmService.mContext.getContentResolver(), USER_SETUP_COMPLETE, 0, mUserId) != 0;
-        if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
-            // If the activity itself has requested auto-remove, then just always do it.
-            autoRemoveRecents = true;
-        } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS))
-                == FLAG_ACTIVITY_NEW_DOCUMENT) {
-            // If the caller has not asked for the document to be retained, then we may
-            // want to turn on auto-remove, depending on whether the target has set its
-            // own document launch mode.
-            if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
-                autoRemoveRecents = false;
-            } else {
-                autoRemoveRecents = true;
-            }
-        } else {
-            autoRemoveRecents = false;
-        }
-        if (mResizeMode != info.resizeMode) {
-            mResizeMode = info.resizeMode;
-            updateTaskDescription();
-        }
-        mSupportsPictureInPicture = info.supportsPictureInPicture();
-    }
-
-    /** Sets the original minimal width and height. */
-    private void setMinDimensions(ActivityInfo info) {
-        if (info != null && info.windowLayout != null) {
-            mMinWidth = info.windowLayout.minWidth;
-            mMinHeight = info.windowLayout.minHeight;
-        } else {
-            mMinWidth = INVALID_MIN_SIZE;
-            mMinHeight = INVALID_MIN_SIZE;
-        }
-    }
-
-    /**
-     * Return true if the input activity has the same intent filter as the intent this task
-     * record is based on (normally the root activity intent).
-     */
-    boolean isSameIntentFilter(ActivityRecord r) {
-        final Intent intent = new Intent(r.intent);
-        // Make sure the component are the same if the input activity has the same real activity
-        // as the one in the task because either one of them could be the alias activity.
-        if (Objects.equals(realActivity, r.mActivityComponent) && this.intent != null) {
-            intent.setComponent(this.intent.getComponent());
-        }
-        return intent.filterEquals(this.intent);
-    }
-
-    boolean returnsToHomeStack() {
-        final int returnHomeFlags = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME;
-        return intent != null && (intent.getFlags() & returnHomeFlags) == returnHomeFlags;
-    }
-
-    void setPrevAffiliate(TaskRecord prevAffiliate) {
-        mPrevAffiliate = prevAffiliate;
-        mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.mTaskId;
-    }
-
-    void setNextAffiliate(TaskRecord nextAffiliate) {
-        mNextAffiliate = nextAffiliate;
-        mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.mTaskId;
-    }
-
-    ActivityStack getStack() {
-        return mStack;
-    }
-
-    // TODO(stack-unify): Can be removed on stack unified.
-    void onParentChanged(ActivityStack newParent, ActivityStack oldParent) {
-        onParentChanged(
-                newParent != null ? newParent.mTaskStack : null,
-                oldParent != null ? oldParent.mTaskStack : null);
-    }
-
-    @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        final ActivityStack oldStack = (oldParent != null)
-                ? ((TaskStack) oldParent).mActivityStack : null;
-        final ActivityStack newStack = (newParent != null)
-                ? ((TaskStack) newParent).mActivityStack : null;
-
-        mStack = newStack;
-
-        super.onParentChanged(newParent, oldParent);
-
-        if (oldStack != null) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityRecord activity = getChildAt(i);
-                oldStack.onActivityRemovedFromStack(activity);
-            }
-
-            updateTaskMovement(true /*toFront*/);
-
-            if (oldStack.inPinnedWindowingMode()
-                    && (newStack == null || !newStack.inPinnedWindowingMode())) {
-                // Notify if a task from the pinned stack is being removed
-                // (or moved depending on the mode).
-                mAtmService.getTaskChangeNotificationController().notifyActivityUnpinned();
-            }
-        }
-
-        if (newStack != null) {
-            for (int i = getChildCount() - 1; i >= 0; --i) {
-                final ActivityRecord activity = getChildAt(i);
-                newStack.onActivityAddedToStack(activity);
-            }
-
-            // TODO: Ensure that this is actually necessary here
-            // Notify the voice session if required
-            if (voiceSession != null) {
-                try {
-                    voiceSession.taskStarted(intent, mTaskId);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
-        // First time we are adding the task to the system.
-        if (oldParent == null && newParent != null) {
-
-            // TODO: Super random place to be doing this, but aligns with what used to be done
-            // before we unified Task level. Look into if this can be done in a better place.
-            updateOverrideConfigurationFromLaunchBounds();
-        }
-
-        // Task is being removed.
-        if (oldParent != null && newParent == null) {
-            cleanUpResourcesForDestroy();
-        }
-
-
-        // Update task bounds if needed.
-        adjustBoundsForDisplayChangeIfNeeded(getDisplayContent());
-
-        if (getWindowConfiguration().windowsAreScaleable()) {
-            // We force windows out of SCALING_MODE_FREEZE so that we can continue to animate them
-            // while a resize is pending.
-            forceWindowsScaleable(true /* force */);
-        } else {
-            forceWindowsScaleable(false /* force */);
-        }
-
-        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
-    }
-
-    /** TODO(task-merge): Consolidate into {@link TaskStack#onChildPositionChanged}. */
-    void updateTaskMovement(boolean toFront) {
-        if (isPersistable) {
-            mLastTimeMoved = System.currentTimeMillis();
-            // Sign is used to keep tasks sorted when persisted. Tasks sent to the bottom most
-            // recently will be most negative, tasks sent to the bottom before that will be less
-            // negative. Similarly for recent tasks moved to the top which will be most positive.
-            if (!toFront) {
-                mLastTimeMoved *= -1;
-            }
-        }
-        mAtmService.mRootActivityContainer.invalidateTaskLayers();
-    }
-
-    /**
-     * @return Id of current stack, {@link ActivityTaskManager#INVALID_STACK_ID} if no stack is set.
-     */
-    int getStackId() {
-        return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
-    }
-
-    // Close up recents linked list.
-    private void closeRecentsChain() {
-        if (mPrevAffiliate != null) {
-            mPrevAffiliate.setNextAffiliate(mNextAffiliate);
-        }
-        if (mNextAffiliate != null) {
-            mNextAffiliate.setPrevAffiliate(mPrevAffiliate);
-        }
-        setPrevAffiliate(null);
-        setNextAffiliate(null);
-    }
-
-    void removedFromRecents() {
-        closeRecentsChain();
-        if (inRecents) {
-            inRecents = false;
-            mAtmService.notifyTaskPersisterLocked(this, false);
-        }
-
-        clearRootProcess();
-
-        mAtmService.mWindowManager.mTaskSnapshotController.notifyTaskRemovedFromRecents(
-                mTaskId, mUserId);
-    }
-
-    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
-        closeRecentsChain();
-        mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId;
-        mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor;
-        // Find the end
-        while (taskToAffiliateWith.mNextAffiliate != null) {
-            final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate;
-            if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) {
-                Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId="
-                        + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId);
-                if (nextRecents.mPrevAffiliate == taskToAffiliateWith) {
-                    nextRecents.setPrevAffiliate(null);
-                }
-                taskToAffiliateWith.setNextAffiliate(null);
-                break;
-            }
-            taskToAffiliateWith = nextRecents;
-        }
-        taskToAffiliateWith.setNextAffiliate(this);
-        setPrevAffiliate(taskToAffiliateWith);
-        setNextAffiliate(null);
-    }
-
-    /** Returns the intent for the root activity for this task */
-    Intent getBaseIntent() {
-        return intent != null ? intent : affinityIntent;
-    }
-
-    /** Returns the first non-finishing activity from the bottom. */
-    ActivityRecord getRootActivity() {
-        final int rootActivityIndex = findRootIndex(false /* effectiveRoot */);
-        if (rootActivityIndex == -1) {
-            // There are no non-finishing activities in the task.
-            return null;
-        }
-        return getChildAt(rootActivityIndex);
-    }
-
-    ActivityRecord getTopActivity() {
-        return getTopActivity(true /* includeOverlays */);
-    }
-
-    ActivityRecord getTopActivity(boolean includeOverlays) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.finishing || (!includeOverlays && r.mTaskOverlay)) {
-                continue;
-            }
-            return r;
-        }
-        return null;
-    }
-
-    ActivityRecord topRunningActivityLocked() {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (!r.finishing && r.okToShowLocked()) {
-                    return r;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Return true if any activities in this task belongs to input uid.
-     */
-    boolean containsAppUid(int uid) {
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.getUid() == uid) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (!r.finishing && r.okToShowLocked() && r.visibleIgnoringKeyguard) {
-                    outActivities.add(r);
-                }
-            }
-        }
-    }
-
-    ActivityRecord topRunningActivityWithStartingWindowLocked() {
-        if (mStack != null) {
-            for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-                ActivityRecord r = getChildAt(activityNdx);
-                if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
-                        || r.finishing || !r.okToShowLocked()) {
-                    continue;
-                }
-                return r;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Return the number of running activities, and the number of non-finishing/initializing
-     * activities in the provided {@param reportOut} respectively.
-     */
-    void getNumRunningActivities(TaskActivitiesReport reportOut) {
-        reportOut.reset();
-        for (int i = getChildCount() - 1; i >= 0; --i) {
-            final ActivityRecord r = getChildAt(i);
-            if (r.finishing) {
-                continue;
-            }
-
-            reportOut.base = r;
-
-            // Increment the total number of non-finishing activities
-            reportOut.numActivities++;
-
-            if (reportOut.top == null || (reportOut.top.isState(ActivityState.INITIALIZING))) {
-                reportOut.top = r;
-                // Reset the number of running activities until we hit the first non-initializing
-                // activity
-                reportOut.numRunning = 0;
-            }
-            if (r.attachedToProcess()) {
-                // Increment the number of actually running activities
-                reportOut.numRunning++;
-            }
-        }
-    }
-
-    boolean okToShowLocked() {
-        // NOTE: If {@link TaskRecord#topRunningActivity} return is not null then it is
-        // okay to show the activity when locked.
-        return mAtmService.mStackSupervisor.isCurrentProfileLocked(mUserId)
-                || topRunningActivityLocked() != null;
-    }
-
-    /**
-     * Reorder the history stack so that the passed activity is brought to the front.
-     */
-    final void moveActivityToFrontLocked(ActivityRecord newTop) {
-        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, "Removing and adding activity "
-                + newTop + " to stack at top callers=" + Debug.getCallers(4));
-
-        positionChildAtTop(newTop);
-        updateEffectiveIntent();
-    }
-
-    @Override
-    /*@WindowConfiguration.ActivityType*/
-    public int getActivityType() {
-        final int applicationType = super.getActivityType();
-        if (applicationType != ACTIVITY_TYPE_UNDEFINED || !hasChild()) {
-            return applicationType;
-        }
-        return getChildAt(0).getActivityType();
-    }
-
-    @Override
-    void addChild(ActivityRecord r, int index) {
-        if (r.getParent() != null) {
-            // Shouldn't already have a parent since we are just adding to the task...Maybe you
-            // meant to use reparent?
-            throw new IllegalStateException(
-                    "r=" + r + " parent=" + r.getParent() + " task=" + this);
-        }
-
-        // If this task had any child before we added this one.
-        boolean hadChild = hasChild();
-
-        index = getAdjustedAddPosition(r, index);
-        super.addChild(r, index);
-
-        ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addChild: %s at top.", this);
-        r.inHistory = true;
-
-        if (r.occludesParent()) {
-            numFullscreen++;
-        }
-        // Only set this based on the first activity
-        if (!hadChild) {
-            if (r.getActivityType() == ACTIVITY_TYPE_UNDEFINED) {
-                // Normally non-standard activity type for the activity record will be set when the
-                // object is created, however we delay setting the standard application type until
-                // this point so that the task can set the type for additional activities added in
-                // the else condition below.
-                r.setActivityType(ACTIVITY_TYPE_STANDARD);
-            }
-            setActivityType(r.getActivityType());
-            isPersistable = r.isPersistable();
-            mCallingUid = r.launchedFromUid;
-            mCallingPackage = r.launchedFromPackage;
-            // Clamp to [1, max].
-            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
-                    ActivityTaskManager.getMaxAppRecentsLimitStatic());
-        } else {
-            // Otherwise make all added activities match this one.
-            r.setActivityType(getActivityType());
-        }
-
-        updateEffectiveIntent();
-        if (r.isPersistable()) {
-            mAtmService.notifyTaskPersisterLocked(this, false);
-        }
-
-        // Make sure the list of display UID whitelists is updated
-        // now that this record is in a new task.
-        mAtmService.mRootActivityContainer.updateUIDsPresentOnDisplay();
-    }
-
-    void addChild(ActivityRecord r) {
-        addChild(r, Integer.MAX_VALUE /* add on top */);
-    }
-
-    @Override
-    void removeChild(ActivityRecord r) {
-        removeChild(r, "removeChild");
-    }
-
-    void removeChild(ActivityRecord r, String reason) {
-        if (!mChildren.contains(r)) {
-            Slog.e(TAG, "removeChild: r=" + r + " not found in t=" + this);
-            return;
-        }
-
-        super.removeChild(r);
-        if (r.occludesParent()) {
-            numFullscreen--;
-        }
-        if (r.isPersistable()) {
-            mAtmService.notifyTaskPersisterLocked(this, false);
-        }
-
-        if (inPinnedWindowingMode()) {
-            // We normally notify listeners of task stack changes on pause, however pinned stack
-            // activities are normally in the paused state so no notification will be sent there
-            // before the activity is removed. We send it here so instead.
-            mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged();
-        }
-
-        if (hasChild()) {
-            updateEffectiveIntent();
-
-            // The following block can be executed multiple times if there is more than one overlay.
-            // {@link ActivityStackSupervisor#removeTaskByIdLocked} handles this by reverse lookup
-            // of the task by id and exiting early if not found.
-            if (onlyHasTaskOverlayActivities(false /* excludingFinishing */)) {
-                // When destroying a task, tell the supervisor to remove it so that any activity it
-                // has can be cleaned up correctly. This is currently the only place where we remove
-                // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
-                // state into removeChild(), we just clear the task here before the other residual
-                // work.
-                // TODO: If the callers to removeChild() changes such that we have multiple places
-                //       where we are destroying the task, move this back into removeChild()
-                mAtmService.mStackSupervisor.removeTaskByIdLocked(mTaskId, false /* killProcess */,
-                        !REMOVE_FROM_RECENTS, reason);
-            }
-        } else if (!mReuseTask) {
-            // Remove entire task if it doesn't have any activity left and it isn't marked for reuse
-            mStack.removeChild(this, reason);
-            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId,
-                    "removeChild: last r=" + r + " in t=" + this);
-            removeIfPossible();
-        }
-    }
-
-    /**
-     * @return whether or not there are ONLY task overlay activities in the stack.
-     *         If {@param excludeFinishing} is set, then ignore finishing activities in the check.
-     *         If there are no task overlay activities, this call returns false.
-     */
-    boolean onlyHasTaskOverlayActivities(boolean excludeFinishing) {
-        int count = 0;
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord r = getChildAt(i);
-            if (excludeFinishing && r.finishing) {
-                continue;
-            }
-            if (!r.mTaskOverlay) {
-                return false;
-            }
-            count++;
-        }
-        return count > 0;
-    }
-
-    boolean autoRemoveFromRecents() {
-        // We will automatically remove the task either if it has explicitly asked for
-        // this, or it is empty and has never contained an activity that got shown to
-        // the user.
-        return autoRemoveRecents || (!hasChild() && !hasBeenVisible);
-    }
-
-    /**
-     * Completely remove all activities associated with an existing
-     * task starting at a specified index.
-     */
-    private void performClearTaskAtIndexLocked(int activityNdx, String reason) {
-        int numActivities = getChildCount();
-        for ( ; activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
-            }
-            if (mStack == null) {
-                // Task was restored from persistent storage.
-                r.takeFromHistory();
-                removeChild(r);
-                --activityNdx;
-                --numActivities;
-            } else if (r.finishIfPossible(Activity.RESULT_CANCELED, null /* resultData */, reason,
-                    false /* oomAdj */)
-                    == FINISH_RESULT_REMOVED) {
-                --activityNdx;
-                --numActivities;
-            }
-        }
-    }
-
-    /**
-     * Completely remove all activities associated with an existing task.
-     */
-    void performClearTaskLocked() {
-        mReuseTask = true;
-        performClearTaskAtIndexLocked(0, "clear-task-all");
-        mReuseTask = false;
-    }
-
-    ActivityRecord performClearTaskForReuseLocked(ActivityRecord newR, int launchFlags) {
-        mReuseTask = true;
-        final ActivityRecord result = performClearTaskLocked(newR, launchFlags);
-        mReuseTask = false;
-        return result;
-    }
-
-    /**
-     * Perform clear operation as requested by
-     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
-     * stack to the given task, then look for
-     * an instance of that activity in the stack and, if found, finish all
-     * activities on top of it and return the instance.
-     *
-     * @param newR Description of the new activity being started.
-     * @return Returns the old activity that should be continued to be used,
-     * or null if none was found.
-     */
-    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
-        int numActivities = getChildCount();
-        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
-            }
-            if (r.mActivityComponent.equals(newR.mActivityComponent)) {
-                // Here it is!  Now finish everything in front...
-                final ActivityRecord ret = r;
-
-                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
-                    r = getChildAt(activityNdx);
-                    if (r.finishing) {
-                        continue;
-                    }
-                    ActivityOptions opts = r.takeOptionsLocked(false /* fromClient */);
-                    if (opts != null) {
-                        ret.updateOptionsLocked(opts);
-                    }
-                    if (r.finishIfPossible("clear-task-stack", false /* oomAdj */)
-                            == FINISH_RESULT_REMOVED) {
-                        --activityNdx;
-                        --numActivities;
-                    }
-                }
-
-                // Finally, if this is a normal launch mode (that is, not
-                // expecting onNewIntent()), then we will finish the current
-                // instance of the activity so a new fresh one can be started.
-                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
-                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
-                        && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
-                    if (!ret.finishing) {
-                        ret.finishIfPossible("clear-task-top", false /* oomAdj */);
-                        return null;
-                    }
-                }
-
-                return ret;
-            }
-        }
-
-        return null;
-    }
-
-    void removeTaskActivitiesLocked(String reason) {
-        // Just remove the entire task.
-        performClearTaskAtIndexLocked(0, reason);
-    }
-
-    String lockTaskAuthToString() {
-        switch (mLockTaskAuth) {
-            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
-            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
-            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
-            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
-            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
-            default: return "unknown=" + mLockTaskAuth;
-        }
-    }
-
-    void setLockTaskAuth() {
-        setLockTaskAuth(getRootActivity());
-    }
-
-    private void setLockTaskAuth(@Nullable ActivityRecord r) {
-        if (r == null) {
-            mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
-            return;
-        }
-
-        final String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
-        final LockTaskController lockTaskController = mAtmService.getLockTaskController();
-        switch (r.lockTaskLaunchMode) {
-            case LOCK_TASK_LAUNCH_MODE_DEFAULT:
-                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
-                        ? LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
-                break;
-
-            case LOCK_TASK_LAUNCH_MODE_NEVER:
-                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
-                break;
-
-            case LOCK_TASK_LAUNCH_MODE_ALWAYS:
-                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-                break;
-
-            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
-                mLockTaskAuth = lockTaskController.isPackageWhitelisted(mUserId, pkg)
-                        ? LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
-                break;
-        }
-        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
-                " mLockTaskAuth=" + lockTaskAuthToString());
-    }
-
-    @Override
-    public boolean supportsSplitScreenWindowingMode() {
-        // A task can not be docked even if it is considered resizeable because it only supports
-        // picture-in-picture mode but has a non-resizeable resizeMode
-        return super.supportsSplitScreenWindowingMode()
-                // TODO(task-group): Probably makes sense to move this and associated code into
-                // WindowContainer so it affects every node.
-                && mAtmService.mSupportsSplitScreenMultiWindow
-                && (mAtmService.mForceResizableActivities
-                        || (isResizeable(false /* checkSupportsPip */)
-                                && !ActivityInfo.isPreserveOrientationMode(mResizeMode)));
-    }
-
-    /**
-     * Check whether this task can be launched on the specified display.
-     *
-     * @param displayId Target display id.
-     * @return {@code true} if either it is the default display or this activity can be put on a
-     *         secondary display.
-     */
-    boolean canBeLaunchedOnDisplay(int displayId) {
-        return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
-                -1 /* don't check PID */, -1 /* don't check UID */, null /* activityInfo */);
-    }
-
-    /**
-     * Check that a given bounds matches the application requested orientation.
-     *
-     * @param bounds The bounds to be tested.
-     * @return True if the requested bounds are okay for a resizing request.
-     */
-    private boolean canResizeToBounds(Rect bounds) {
-        if (bounds == null || !inFreeformWindowingMode()) {
-            // Note: If not on the freeform workspace, we ignore the bounds.
-            return true;
-        }
-        final boolean landscape = bounds.width() > bounds.height();
-        final Rect configBounds = getRequestedOverrideBounds();
-        if (mResizeMode == RESIZE_MODE_FORCE_RESIZABLE_PRESERVE_ORIENTATION) {
-            return configBounds.isEmpty()
-                    || landscape == (configBounds.width() > configBounds.height());
-        }
-        return (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_PORTRAIT_ONLY || !landscape)
-                && (mResizeMode != RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY || landscape);
-    }
-
-    /**
-     * @return {@code true} if the task is being cleared for the purposes of being reused.
-     */
-    boolean isClearingToReuseTask() {
-        return mReuseTask;
-    }
-
-    /**
-     * Find the activity in the history stack within the given task.  Returns
-     * the index within the history at which it's found, or < 0 if not found.
-     */
-    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
-        final ComponentName realActivity = r.mActivityComponent;
-        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            ActivityRecord candidate = getChildAt(activityNdx);
-            if (candidate.finishing) {
-                continue;
-            }
-            if (candidate.mActivityComponent.equals(realActivity)) {
-                return candidate;
-            }
-        }
-        return null;
-    }
-
-    /** Updates the last task description values. */
-    void updateTaskDescription() {
-        // TODO(AM refactor): Cleanup to use findRootIndex()
-        // Traverse upwards looking for any break between main task activities and
-        // utility activities.
-        int activityNdx;
-        final int numActivities = getChildCount();
-        final boolean relinquish = numActivities != 0 &&
-                (getChildAt(0).info.flags & FLAG_RELINQUISH_TASK_IDENTITY) != 0;
-        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
-                ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (relinquish && (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
-                // This will be the top activity for determining taskDescription. Pre-inc to
-                // overcome initial decrement below.
-                ++activityNdx;
-                break;
-            }
-            if (r.intent != null &&
-                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-                break;
-            }
-        }
-        if (activityNdx > 0) {
-            // Traverse downwards starting below break looking for set label, icon.
-            // Note that if there are activities in the task but none of them set the
-            // recent activity values, then we do not fall back to the last set
-            // values in the TaskRecord.
-            String label = null;
-            String iconFilename = null;
-            int iconResource = -1;
-            int colorPrimary = 0;
-            int colorBackground = 0;
-            int statusBarColor = 0;
-            int navigationBarColor = 0;
-            boolean statusBarContrastWhenTransparent = false;
-            boolean navigationBarContrastWhenTransparent = false;
-            boolean topActivity = true;
-            for (--activityNdx; activityNdx >= 0; --activityNdx) {
-                final ActivityRecord r = getChildAt(activityNdx);
-                if (r.mTaskOverlay) {
-                    continue;
-                }
-                if (r.taskDescription != null) {
-                    if (label == null) {
-                        label = r.taskDescription.getLabel();
-                    }
-                    if (iconResource == -1) {
-                        iconResource = r.taskDescription.getIconResource();
-                    }
-                    if (iconFilename == null) {
-                        iconFilename = r.taskDescription.getIconFilename();
-                    }
-                    if (colorPrimary == 0) {
-                        colorPrimary = r.taskDescription.getPrimaryColor();
-                    }
-                    if (topActivity) {
-                        colorBackground = r.taskDescription.getBackgroundColor();
-                        statusBarColor = r.taskDescription.getStatusBarColor();
-                        navigationBarColor = r.taskDescription.getNavigationBarColor();
-                        statusBarContrastWhenTransparent =
-                                r.taskDescription.getEnsureStatusBarContrastWhenTransparent();
-                        navigationBarContrastWhenTransparent =
-                                r.taskDescription.getEnsureNavigationBarContrastWhenTransparent();
-                    }
-                }
-                topActivity = false;
-            }
-            final TaskDescription taskDescription = new TaskDescription(label, null, iconResource,
-                    iconFilename, colorPrimary, colorBackground, statusBarColor, navigationBarColor,
-                    statusBarContrastWhenTransparent, navigationBarContrastWhenTransparent,
-                    mResizeMode, mMinWidth, mMinHeight);
-            setTaskDescription(taskDescription);
-            // Update the task affiliation color if we are the parent of the group
-            if (mTaskId == mAffiliatedTaskId) {
-                mAffiliatedTaskColor = taskDescription.getPrimaryColor();
-            }
-            mAtmService.getTaskChangeNotificationController().notifyTaskDescriptionChanged(
-                    getTaskInfo());
-        }
-    }
-
-    /**
-     * Find the index of the root activity in the task. It will be the first activity from the
-     * bottom that is not finishing.
-     *
-     * @param effectiveRoot Flag indicating whether 'effective root' should be returned - an
-     *                      activity that defines the task identity (its base intent). It's the
-     *                      first one that does not have
-     *                      {@link ActivityInfo#FLAG_RELINQUISH_TASK_IDENTITY}.
-     * @return index of the 'root' or 'effective' root in the list of activities, -1 if no eligible
-     *         activity was found.
-     */
-    int findRootIndex(boolean effectiveRoot) {
-        int effectiveNdx = -1;
-        final int topActivityNdx = getChildCount() - 1;
-        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.finishing) {
-                continue;
-            }
-            effectiveNdx = activityNdx;
-            if (!effectiveRoot || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
-                break;
-            }
-        }
-        return effectiveNdx;
-    }
-
-    // TODO (AM refactor): Invoke automatically when there is a change in children
-    @VisibleForTesting
-    void updateEffectiveIntent() {
-        int effectiveRootIndex = findRootIndex(true /* effectiveRoot */);
-        if (effectiveRootIndex == -1) {
-            // All activities in the task are either finishing or relinquish task identity.
-            // But we still want to update the intent, so let's use the bottom activity.
-            effectiveRootIndex = 0;
-        }
-        final ActivityRecord r = getChildAt(effectiveRootIndex);
-        setIntent(r);
-
-        // Update the task description when the activities change
-        updateTaskDescription();
-    }
-
-    void adjustForMinimalTaskDimensions(Rect bounds, Rect previousBounds) {
-        if (bounds == null) {
-            return;
-        }
-        int minWidth = mMinWidth;
-        int minHeight = mMinHeight;
-        // If the task has no requested minimal size, we'd like to enforce a minimal size
-        // so that the user can not render the task too small to manipulate. We don't need
-        // to do this for the pinned stack as the bounds are controlled by the system.
-        if (!inPinnedWindowingMode() && mStack != null) {
-            final int defaultMinSizeDp =
-                    mAtmService.mRootActivityContainer.mDefaultMinSizeOfResizeableTaskDp;
-            final ActivityDisplay display =
-                    mAtmService.mRootActivityContainer.getActivityDisplay(mStack.mDisplayId);
-            final float density =
-                    (float) display.getConfiguration().densityDpi / DisplayMetrics.DENSITY_DEFAULT;
-            final int defaultMinSize = (int) (defaultMinSizeDp * density);
-
-            if (minWidth == INVALID_MIN_SIZE) {
-                minWidth = defaultMinSize;
-            }
-            if (minHeight == INVALID_MIN_SIZE) {
-                minHeight = defaultMinSize;
-            }
-        }
-        final boolean adjustWidth = minWidth > bounds.width();
-        final boolean adjustHeight = minHeight > bounds.height();
-        if (!(adjustWidth || adjustHeight)) {
-            return;
-        }
-
-        if (adjustWidth) {
-            if (!previousBounds.isEmpty() && bounds.right == previousBounds.right) {
-                bounds.left = bounds.right - minWidth;
-            } else {
-                // Either left bounds match, or neither match, or the previous bounds were
-                // fullscreen and we default to keeping left.
-                bounds.right = bounds.left + minWidth;
-            }
-        }
-        if (adjustHeight) {
-            if (!previousBounds.isEmpty() && bounds.bottom == previousBounds.bottom) {
-                bounds.top = bounds.bottom - minHeight;
-            } else {
-                // Either top bounds match, or neither match, or the previous bounds were
-                // fullscreen and we default to keeping top.
-                bounds.bottom = bounds.top + minHeight;
-            }
-        }
-    }
-
-    void setLastNonFullscreenBounds(Rect bounds) {
-        if (mLastNonFullscreenBounds == null) {
-            mLastNonFullscreenBounds = new Rect(bounds);
-        } else {
-            mLastNonFullscreenBounds.set(bounds);
-        }
-    }
-
-    /**
-     * This should be called when an child activity changes state. This should only
-     * be called from
-     * {@link ActivityRecord#setState(ActivityState, String)} .
-     * @param record The {@link ActivityRecord} whose state has changed.
-     * @param state The new state.
-     * @param reason The reason for the change.
-     */
-    void onActivityStateChanged(ActivityRecord record, ActivityState state, String reason) {
-        final ActivityStack parent = getStack();
-
-        if (parent != null) {
-            parent.onActivityStateChanged(record, state, reason);
-        }
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        // Check if the new configuration supports persistent bounds (eg. is Freeform) and if so
-        // restore the last recorded non-fullscreen bounds.
-        final boolean prevPersistTaskBounds = getWindowConfiguration().persistTaskBounds();
-        final boolean nextPersistTaskBounds =
-                getRequestedOverrideConfiguration().windowConfiguration.persistTaskBounds()
-                || newParentConfig.windowConfiguration.persistTaskBounds();
-        if (!prevPersistTaskBounds && nextPersistTaskBounds
-                && mLastNonFullscreenBounds != null && !mLastNonFullscreenBounds.isEmpty()) {
-            // Bypass onRequestedOverrideConfigurationChanged here to avoid infinite loop.
-            getRequestedOverrideConfiguration().windowConfiguration
-                    .setBounds(mLastNonFullscreenBounds);
-        }
-
-        final boolean wasInMultiWindowMode = inMultiWindowMode();
-        super.onConfigurationChanged(newParentConfig);
-        if (wasInMultiWindowMode != inMultiWindowMode()) {
-            mAtmService.mStackSupervisor.scheduleUpdateMultiWindowMode(this);
-        }
-
-        // If the configuration supports persistent bounds (eg. Freeform), keep track of the
-        // current (non-fullscreen) bounds for persistence.
-        if (getWindowConfiguration().persistTaskBounds()) {
-            final Rect currentBounds = getRequestedOverrideBounds();
-            if (!currentBounds.isEmpty()) {
-                setLastNonFullscreenBounds(currentBounds);
-            }
-        }
-        // TODO: Should also take care of Pip mode changes here.
-
-        saveLaunchingStateIfNeeded();
-    }
-
-    /**
-     * Saves launching state if necessary so that we can launch the activity to its latest state.
-     * It only saves state if this task has been shown to user and it's in fullscreen or freeform
-     * mode on freeform displays.
-     */
-    void saveLaunchingStateIfNeeded() {
-        if (!hasBeenVisible) {
-            // Not ever visible to user.
-            return;
-        }
-
-        final int windowingMode = getWindowingMode();
-        if (windowingMode != WINDOWING_MODE_FULLSCREEN
-                && windowingMode != WINDOWING_MODE_FREEFORM) {
-            return;
-        }
-
-        // Don't persist state if display isn't in freeform mode. Then the task will be launched
-        // back to its last state in a freeform display when it's launched in a freeform display
-        // next time.
-        if (getWindowConfiguration().getDisplayWindowingMode() != WINDOWING_MODE_FREEFORM) {
-            return;
-        }
-
-        // Saves the new state so that we can launch the activity at the same location.
-        mAtmService.mStackSupervisor.mLaunchParamsPersister.saveTask(this);
-    }
-
-    /**
-     * Adjust bounds to stay within stack bounds.
-     *
-     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
-     * that keep them unchanged, but be contained within the stack bounds.
-     *
-     * @param bounds Bounds to be adjusted.
-     * @param stackBounds Bounds within which the other bounds should remain.
-     * @param overlapPxX The amount of px required to be visible in the X dimension.
-     * @param overlapPxY The amount of px required to be visible in the Y dimension.
-     */
-    private static void fitWithinBounds(Rect bounds, Rect stackBounds, int overlapPxX,
-            int overlapPxY) {
-        if (stackBounds == null || stackBounds.isEmpty() || stackBounds.contains(bounds)) {
-            return;
-        }
-
-        // For each side of the parent (eg. left), check if the opposing side of the window (eg.
-        // right) is at least overlap pixels away. If less, offset the window by that difference.
-        int horizontalDiff = 0;
-        // If window is smaller than overlap, use it's smallest dimension instead
-        int overlapLR = Math.min(overlapPxX, bounds.width());
-        if (bounds.right < (stackBounds.left + overlapLR)) {
-            horizontalDiff = overlapLR - (bounds.right - stackBounds.left);
-        } else if (bounds.left > (stackBounds.right - overlapLR)) {
-            horizontalDiff = -(overlapLR - (stackBounds.right - bounds.left));
-        }
-        int verticalDiff = 0;
-        int overlapTB = Math.min(overlapPxY, bounds.width());
-        if (bounds.bottom < (stackBounds.top + overlapTB)) {
-            verticalDiff = overlapTB - (bounds.bottom - stackBounds.top);
-        } else if (bounds.top > (stackBounds.bottom - overlapTB)) {
-            verticalDiff = -(overlapTB - (stackBounds.bottom - bounds.top));
-        }
-        bounds.offset(horizontalDiff, verticalDiff);
-    }
-
-    /**
-     * Intersects inOutBounds with intersectBounds-intersectInsets. If inOutBounds is larger than
-     * intersectBounds on a side, then the respective side will not be intersected.
-     *
-     * The assumption is that if inOutBounds is initially larger than intersectBounds, then the
-     * inset on that side is no-longer applicable. This scenario happens when a task's minimal
-     * bounds are larger than the provided parent/display bounds.
-     *
-     * @param inOutBounds the bounds to intersect.
-     * @param intersectBounds the bounds to intersect with.
-     * @param intersectInsets insets to apply to intersectBounds before intersecting.
-     */
-    static void intersectWithInsetsIfFits(
-            Rect inOutBounds, Rect intersectBounds, Rect intersectInsets) {
-        if (inOutBounds.right <= intersectBounds.right) {
-            inOutBounds.right =
-                    Math.min(intersectBounds.right - intersectInsets.right, inOutBounds.right);
-        }
-        if (inOutBounds.bottom <= intersectBounds.bottom) {
-            inOutBounds.bottom =
-                    Math.min(intersectBounds.bottom - intersectInsets.bottom, inOutBounds.bottom);
-        }
-        if (inOutBounds.left >= intersectBounds.left) {
-            inOutBounds.left =
-                    Math.max(intersectBounds.left + intersectInsets.left, inOutBounds.left);
-        }
-        if (inOutBounds.top >= intersectBounds.top) {
-            inOutBounds.top =
-                    Math.max(intersectBounds.top + intersectInsets.top, inOutBounds.top);
-        }
-    }
-
-    /**
-     * Gets bounds with non-decor and stable insets applied respectively.
-     *
-     * If bounds overhangs the display, those edges will not get insets. See
-     * {@link #intersectWithInsetsIfFits}
-     *
-     * @param outNonDecorBounds where to place bounds with non-decor insets applied.
-     * @param outStableBounds where to place bounds with stable insets applied.
-     * @param bounds the bounds to inset.
-     */
-    private void calculateInsetFrames(Rect outNonDecorBounds, Rect outStableBounds, Rect bounds,
-            DisplayInfo displayInfo) {
-        outNonDecorBounds.set(bounds);
-        outStableBounds.set(bounds);
-        if (getStack() == null || getStack().getDisplay() == null) {
-            return;
-        }
-        DisplayPolicy policy = getStack().getDisplay().mDisplayContent.getDisplayPolicy();
-        if (policy == null) {
-            return;
-        }
-        mTmpBounds.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
-
-        policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth,
-                displayInfo.logicalHeight, displayInfo.displayCutout, mTmpInsets);
-        intersectWithInsetsIfFits(outNonDecorBounds, mTmpBounds, mTmpInsets);
-
-        policy.convertNonDecorInsetsToStableInsets(mTmpInsets, displayInfo.rotation);
-        intersectWithInsetsIfFits(outStableBounds, mTmpBounds, mTmpInsets);
-    }
-
-    /**
-     * Asks docked-divider controller for the smallestwidthdp given bounds.
-     * @param bounds bounds to calculate smallestwidthdp for.
-     */
-    private int getSmallestScreenWidthDpForDockedBounds(Rect bounds) {
-        DisplayContent dc = mStack.getDisplay().mDisplayContent;
-        if (dc != null) {
-            return dc.getDockedDividerController().getSmallestWidthDpForBounds(bounds);
-        }
-        return Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED;
-    }
-
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig) {
-        computeConfigResourceOverrides(inOutConfig, parentConfig, null /* compatInsets */);
-    }
-
-    /**
-     * Calculates configuration values used by the client to get resources. This should be run
-     * using app-facing bounds (bounds unmodified by animations or transient interactions).
-     *
-     * This assumes bounds are non-empty/null. For the null-bounds case, the caller is likely
-     * configuring an "inherit-bounds" window which means that all configuration settings would
-     * just be inherited from the parent configuration.
-     **/
-    void computeConfigResourceOverrides(@NonNull Configuration inOutConfig,
-            @NonNull Configuration parentConfig,
-            @Nullable ActivityRecord.CompatDisplayInsets compatInsets) {
-        int windowingMode = inOutConfig.windowConfiguration.getWindowingMode();
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = parentConfig.windowConfiguration.getWindowingMode();
-        }
-
-        float density = inOutConfig.densityDpi;
-        if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-            density = parentConfig.densityDpi;
-        }
-        density *= DisplayMetrics.DENSITY_DEFAULT_SCALE;
-
-        final Rect bounds = inOutConfig.windowConfiguration.getBounds();
-        Rect outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
-        if (outAppBounds == null || outAppBounds.isEmpty()) {
-            inOutConfig.windowConfiguration.setAppBounds(bounds);
-            outAppBounds = inOutConfig.windowConfiguration.getAppBounds();
-        }
-        // Non-null compatibility insets means the activity prefers to keep its original size, so
-        // the out bounds doesn't need to be restricted by the parent.
-        final boolean insideParentBounds = compatInsets == null;
-        if (insideParentBounds && windowingMode != WINDOWING_MODE_FREEFORM) {
-            final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds();
-            if (parentAppBounds != null && !parentAppBounds.isEmpty()) {
-                outAppBounds.intersect(parentAppBounds);
-            }
-        }
-
-        if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED
-                || inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-            if (insideParentBounds && mStack != null) {
-                final DisplayInfo di = new DisplayInfo();
-                mStack.getDisplay().mDisplay.getDisplayInfo(di);
-
-                // For calculating screenWidthDp, screenWidthDp, we use the stable inset screen
-                // area, i.e. the screen area without the system bars.
-                // The non decor inset are areas that could never be removed in Honeycomb. See
-                // {@link WindowManagerPolicy#getNonDecorInsetsLw}.
-                calculateInsetFrames(mTmpNonDecorBounds, mTmpStableBounds, bounds, di);
-            } else {
-                // Apply the given non-decor and stable insets to calculate the corresponding bounds
-                // for screen size of configuration.
-                int rotation = inOutConfig.windowConfiguration.getRotation();
-                if (rotation == ROTATION_UNDEFINED) {
-                    rotation = parentConfig.windowConfiguration.getRotation();
-                }
-                if (rotation != ROTATION_UNDEFINED && compatInsets != null) {
-                    mTmpNonDecorBounds.set(bounds);
-                    mTmpStableBounds.set(bounds);
-                    compatInsets.getDisplayBoundsByRotation(mTmpBounds, rotation);
-                    intersectWithInsetsIfFits(mTmpNonDecorBounds, mTmpBounds,
-                            compatInsets.mNonDecorInsets[rotation]);
-                    intersectWithInsetsIfFits(mTmpStableBounds, mTmpBounds,
-                            compatInsets.mStableInsets[rotation]);
-                    outAppBounds.set(mTmpNonDecorBounds);
-                } else {
-                    // Set to app bounds because it excludes decor insets.
-                    mTmpNonDecorBounds.set(outAppBounds);
-                    mTmpStableBounds.set(outAppBounds);
-                }
-            }
-
-            if (inOutConfig.screenWidthDp == Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-                final int overrideScreenWidthDp = (int) (mTmpStableBounds.width() / density);
-                inOutConfig.screenWidthDp = insideParentBounds
-                        ? Math.min(overrideScreenWidthDp, parentConfig.screenWidthDp)
-                        : overrideScreenWidthDp;
-            }
-            if (inOutConfig.screenHeightDp == Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-                final int overrideScreenHeightDp = (int) (mTmpStableBounds.height() / density);
-                inOutConfig.screenHeightDp = insideParentBounds
-                        ? Math.min(overrideScreenHeightDp, parentConfig.screenHeightDp)
-                        : overrideScreenHeightDp;
-            }
-
-            if (inOutConfig.smallestScreenWidthDp
-                    == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
-                if (WindowConfiguration.isFloating(windowingMode)) {
-                    // For floating tasks, calculate the smallest width from the bounds of the task
-                    inOutConfig.smallestScreenWidthDp = (int) (
-                            Math.min(bounds.width(), bounds.height()) / density);
-                } else if (WindowConfiguration.isSplitScreenWindowingMode(windowingMode)) {
-                    // Iterating across all screen orientations, and return the minimum of the task
-                    // width taking into account that the bounds might change because the snap
-                    // algorithm snaps to a different value
-                    inOutConfig.smallestScreenWidthDp =
-                            getSmallestScreenWidthDpForDockedBounds(bounds);
-                }
-                // otherwise, it will just inherit
-            }
-        }
-
-        if (inOutConfig.orientation == ORIENTATION_UNDEFINED) {
-            inOutConfig.orientation = (inOutConfig.screenWidthDp <= inOutConfig.screenHeightDp)
-                    ? ORIENTATION_PORTRAIT : ORIENTATION_LANDSCAPE;
-        }
-        if (inOutConfig.screenLayout == Configuration.SCREENLAYOUT_UNDEFINED) {
-            // For calculating screen layout, we need to use the non-decor inset screen area for the
-            // calculation for compatibility reasons, i.e. screen area without system bars that
-            // could never go away in Honeycomb.
-            final int compatScreenWidthDp = (int) (mTmpNonDecorBounds.width() / density);
-            final int compatScreenHeightDp = (int) (mTmpNonDecorBounds.height() / density);
-            // We're only overriding LONG, SIZE and COMPAT parts of screenLayout, so we start
-            // override calculation with partial default.
-            // Reducing the screen layout starting from its parent config.
-            final int sl = parentConfig.screenLayout
-                    & (Configuration.SCREENLAYOUT_LONG_MASK | Configuration.SCREENLAYOUT_SIZE_MASK);
-            final int longSize = Math.max(compatScreenHeightDp, compatScreenWidthDp);
-            final int shortSize = Math.min(compatScreenHeightDp, compatScreenWidthDp);
-            inOutConfig.screenLayout = Configuration.reduceScreenLayout(sl, longSize, shortSize);
-        }
-    }
-
-    @Override
-    void resolveOverrideConfiguration(Configuration newParentConfig) {
-        mTmpBounds.set(getResolvedOverrideConfiguration().windowConfiguration.getBounds());
-        super.resolveOverrideConfiguration(newParentConfig);
-        int windowingMode =
-                getRequestedOverrideConfiguration().windowConfiguration.getWindowingMode();
-        if (windowingMode == WINDOWING_MODE_UNDEFINED) {
-            windowingMode = newParentConfig.windowConfiguration.getWindowingMode();
-        }
-        Rect outOverrideBounds =
-                getResolvedOverrideConfiguration().windowConfiguration.getBounds();
-
-        if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
-            computeFullscreenBounds(outOverrideBounds, null /* refActivity */,
-                    newParentConfig.windowConfiguration.getBounds(),
-                    newParentConfig.orientation);
-        }
-
-        if (outOverrideBounds.isEmpty()) {
-            // If the task fills the parent, just inherit all the other configs from parent.
-            return;
-        }
-
-        adjustForMinimalTaskDimensions(outOverrideBounds, mTmpBounds);
-        if (windowingMode == WINDOWING_MODE_FREEFORM) {
-            // by policy, make sure the window remains within parent somewhere
-            final float density =
-                    ((float) newParentConfig.densityDpi) / DisplayMetrics.DENSITY_DEFAULT;
-            final Rect parentBounds =
-                    new Rect(newParentConfig.windowConfiguration.getBounds());
-            final ActivityDisplay display = mStack.getDisplay();
-            if (display != null && display.mDisplayContent != null) {
-                // If a freeform window moves below system bar, there is no way to move it again
-                // by touch. Because its caption is covered by system bar. So we exclude them
-                // from stack bounds. and then caption will be shown inside stable area.
-                final Rect stableBounds = new Rect();
-                display.mDisplayContent.getStableRect(stableBounds);
-                parentBounds.intersect(stableBounds);
-            }
-
-            fitWithinBounds(outOverrideBounds, parentBounds,
-                    (int) (density * WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP),
-                    (int) (density * WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP));
-
-            // Prevent to overlap caption with stable insets.
-            final int offsetTop = parentBounds.top - outOverrideBounds.top;
-            if (offsetTop > 0) {
-                outOverrideBounds.offset(0, offsetTop);
-            }
-        }
-        computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
-    }
-
-    /**
-     * Compute bounds (letterbox or pillarbox) for
-     * {@link WindowConfiguration#WINDOWING_MODE_FULLSCREEN} when the parent doesn't handle the
-     * orientation change and the requested orientation is different from the parent.
-     */
-    void computeFullscreenBounds(@NonNull Rect outBounds, @Nullable ActivityRecord refActivity,
-            @NonNull Rect parentBounds, int parentOrientation) {
-        // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent".
-        outBounds.setEmpty();
-        if (handlesOrientationChangeFromDescendant()) {
-            return;
-        }
-        if (refActivity == null) {
-            // Use the top activity as the reference of orientation. Don't include overlays because
-            // it is usually not the actual content or just temporarily shown.
-            // E.g. ForcedResizableInfoActivity.
-            refActivity = getTopActivity(false /* includeOverlays */);
-        }
-
-        // If the task or the reference activity requires a different orientation (either by
-        // override or activityInfo), make it fit the available bounds by scaling down its bounds.
-        final int overrideOrientation = getRequestedOverrideConfiguration().orientation;
-        final int forcedOrientation =
-                (overrideOrientation != ORIENTATION_UNDEFINED || refActivity == null)
-                        ? overrideOrientation : refActivity.getRequestedConfigurationOrientation();
-        if (forcedOrientation == ORIENTATION_UNDEFINED || forcedOrientation == parentOrientation) {
-            return;
-        }
-
-        final int parentWidth = parentBounds.width();
-        final int parentHeight = parentBounds.height();
-        final float aspect = ((float) parentHeight) / parentWidth;
-        if (forcedOrientation == ORIENTATION_LANDSCAPE) {
-            final int height = (int) (parentWidth / aspect);
-            final int top = parentBounds.centerY() - height / 2;
-            outBounds.set(parentBounds.left, top, parentBounds.right, top + height);
-        } else {
-            final int width = (int) (parentHeight * aspect);
-            final int left = parentBounds.centerX() - width / 2;
-            outBounds.set(left, parentBounds.top, left + width, parentBounds.bottom);
-        }
-    }
-
-    Rect updateOverrideConfigurationFromLaunchBounds() {
-        final Rect bounds = getLaunchBounds();
-        setBounds(bounds);
-        if (bounds != null && !bounds.isEmpty()) {
-            // TODO: Review if we actually want to do this - we are setting the launch bounds
-            // directly here.
-            bounds.set(getRequestedOverrideBounds());
-        }
-        return bounds;
-    }
-
-    /** Updates the task's bounds and override configuration to match what is expected for the
-     * input stack. */
-    void updateOverrideConfigurationForStack(ActivityStack inStack) {
-        if (mStack != null && mStack == inStack) {
-            return;
-        }
-
-        if (inStack.inFreeformWindowingMode()) {
-            if (!isResizeable()) {
-                throw new IllegalArgumentException("Can not position non-resizeable task="
-                        + this + " in stack=" + inStack);
-            }
-            if (!matchParentBounds()) {
-                return;
-            }
-            if (mLastNonFullscreenBounds != null) {
-                setBounds(mLastNonFullscreenBounds);
-            } else {
-                mAtmService.mStackSupervisor.getLaunchParamsController().layoutTask(this, null);
-            }
-        } else {
-            setBounds(inStack.getRequestedOverrideBounds());
-        }
-    }
-
-    /** Returns the bounds that should be used to launch this task. */
-    Rect getLaunchBounds() {
-        if (mStack == null) {
-            return null;
-        }
-
-        final int windowingMode = getWindowingMode();
-        if (!isActivityTypeStandardOrUndefined()
-                || windowingMode == WINDOWING_MODE_FULLSCREEN
-                || (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && !isResizeable())) {
-            return isResizeable() ? mStack.getRequestedOverrideBounds() : null;
-        } else if (!getWindowConfiguration().persistTaskBounds()) {
-            return mStack.getRequestedOverrideBounds();
-        }
-        return mLastNonFullscreenBounds;
-    }
-
-    void addStartingWindowsForVisibleActivities(boolean taskSwitch) {
-        for (int activityNdx = getChildCount() - 1; activityNdx >= 0; --activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.visible) {
-                r.showStartingWindow(null /* prev */, false /* newTask */, taskSwitch);
-            }
-        }
-    }
-
-    void setRootProcess(WindowProcessController proc) {
-        clearRootProcess();
-        if (intent != null &&
-                (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
-            mRootProcess = proc;
-            mRootProcess.addRecentTask(this);
-        }
-    }
-
-    void clearRootProcess() {
-        if (mRootProcess != null) {
-            mRootProcess.removeRecentTask(this);
-            mRootProcess = null;
-        }
-    }
-
-    void clearAllPendingOptions() {
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            getChildAt(i).clearOptionsLocked(false /* withAbort */);
-        }
-    }
-
-    /**
-     * Fills in a {@link TaskInfo} with information from this task.
-     * @param info the {@link TaskInfo} to fill in
-     */
-    void fillTaskInfo(TaskInfo info) {
-        getNumRunningActivities(mReuseActivitiesReport);
-        info.userId = mUserId;
-        info.stackId = getStackId();
-        info.taskId = mTaskId;
-        info.displayId = mStack == null ? Display.INVALID_DISPLAY : mStack.mDisplayId;
-        info.isRunning = getTopActivity() != null;
-        info.baseIntent = new Intent(getBaseIntent());
-        info.baseActivity = mReuseActivitiesReport.base != null
-                ? mReuseActivitiesReport.base.intent.getComponent()
-                : null;
-        info.topActivity = mReuseActivitiesReport.top != null
-                ? mReuseActivitiesReport.top.mActivityComponent
-                : null;
-        info.origActivity = origActivity;
-        info.realActivity = realActivity;
-        info.numActivities = mReuseActivitiesReport.numActivities;
-        info.lastActiveTime = lastActiveTime;
-        info.taskDescription = new ActivityManager.TaskDescription(getTaskDescription());
-        info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
-        info.resizeMode = mResizeMode;
-        info.configuration.setTo(getConfiguration());
-    }
-
-    /**
-     * Returns a  {@link TaskInfo} with information from this task.
-     */
-    ActivityManager.RunningTaskInfo getTaskInfo() {
-        ActivityManager.RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
-        fillTaskInfo(info);
-        return info;
-    }
-
-    void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.print("userId="); pw.print(mUserId);
-                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
-                pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
-                pw.print(" mUserSetupComplete="); pw.print(mUserSetupComplete);
-                pw.print(" mCallingPackage="); pw.println(mCallingPackage);
-        if (affinity != null || rootAffinity != null) {
-            pw.print(prefix); pw.print("affinity="); pw.print(affinity);
-            if (affinity == null || !affinity.equals(rootAffinity)) {
-                pw.print(" root="); pw.println(rootAffinity);
-            } else {
-                pw.println();
-            }
-        }
-        if (voiceSession != null || voiceInteractor != null) {
-            pw.print(prefix); pw.print("VOICE: session=0x");
-            pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
-            pw.print(" interactor=0x");
-            pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
-        }
-        if (intent != null) {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append(prefix); sb.append("intent={");
-            intent.toShortString(sb, false, true, false, false);
-            sb.append('}');
-            pw.println(sb.toString());
-        }
-        if (affinityIntent != null) {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append(prefix); sb.append("affinityIntent={");
-            affinityIntent.toShortString(sb, false, true, false, false);
-            sb.append('}');
-            pw.println(sb.toString());
-        }
-        if (origActivity != null) {
-            pw.print(prefix); pw.print("origActivity=");
-            pw.println(origActivity.flattenToShortString());
-        }
-        if (realActivity != null) {
-            pw.print(prefix); pw.print("mActivityComponent=");
-            pw.println(realActivity.flattenToShortString());
-        }
-        if (autoRemoveRecents || isPersistable || !isActivityTypeStandard() || numFullscreen != 0) {
-            pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
-                    pw.print(" isPersistable="); pw.print(isPersistable);
-                    pw.print(" numFullscreen="); pw.print(numFullscreen);
-                    pw.print(" activityType="); pw.println(getActivityType());
-        }
-        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
-                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
-            pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
-                    pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
-                    pw.print(" mReuseTask="); pw.print(mReuseTask);
-                    pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
-        }
-        if (mAffiliatedTaskId != mTaskId || mPrevAffiliateTaskId != INVALID_TASK_ID
-                || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
-                || mNextAffiliate != null) {
-            pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
-                    pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
-                    pw.print(" (");
-                    if (mPrevAffiliate == null) {
-                        pw.print("null");
-                    } else {
-                        pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
-                    }
-                    pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
-                    pw.print(" (");
-                    if (mNextAffiliate == null) {
-                        pw.print("null");
-                    } else {
-                        pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
-                    }
-                    pw.println(")");
-        }
-        pw.print(prefix); pw.print("Activities="); pw.println(mChildren);
-        if (!askedCompatMode || !inRecents || !isAvailable) {
-            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
-                    pw.print(" inRecents="); pw.print(inRecents);
-                    pw.print(" isAvailable="); pw.println(isAvailable);
-        }
-        if (lastDescription != null) {
-            pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
-        }
-        if (mRootProcess != null) {
-            pw.print(prefix); pw.print("mRootProcess="); pw.println(mRootProcess);
-        }
-        pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
-        pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
-                pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
-                pw.print(" mSupportsPictureInPicture=" + mSupportsPictureInPicture);
-                pw.print(" isResizeable=" + isResizeable());
-                pw.print(" lastActiveTime=" + lastActiveTime);
-                pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder(128);
-        if (stringName != null) {
-            sb.append(stringName);
-            sb.append(" U=");
-            sb.append(mUserId);
-            sb.append(" StackId=");
-            sb.append(getStackId());
-            sb.append(" sz=");
-            sb.append(getChildCount());
-            sb.append('}');
-            return sb.toString();
-        }
-        sb.append("TaskRecord{");
-        sb.append(Integer.toHexString(System.identityHashCode(this)));
-        sb.append(" #");
-        sb.append(mTaskId);
-        if (affinity != null) {
-            sb.append(" A=");
-            sb.append(affinity);
-        } else if (intent != null) {
-            sb.append(" I=");
-            sb.append(intent.getComponent().flattenToShortString());
-        } else if (affinityIntent != null && affinityIntent.getComponent() != null) {
-            sb.append(" aI=");
-            sb.append(affinityIntent.getComponent().flattenToShortString());
-        } else {
-            sb.append(" ??");
-        }
-        stringName = sb.toString();
-        return toString();
-    }
-
-    @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
-            @WindowTraceLogLevel int logLevel) {
-        if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
-            return;
-        }
-
-        final long token = proto.start(fieldId);
-        writeToProtoInnerTaskOnly(proto, TASK, logLevel);
-        proto.write(ID, mTaskId);
-        for (int i = getChildCount() - 1; i >= 0; i--) {
-            final ActivityRecord activity = getChildAt(i);
-            activity.writeToProto(proto, ACTIVITIES);
-        }
-        proto.write(STACK_ID, getStackId());
-        if (mLastNonFullscreenBounds != null) {
-            mLastNonFullscreenBounds.writeToProto(proto, LAST_NON_FULLSCREEN_BOUNDS);
-        }
-        if (realActivity != null) {
-            proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
-        }
-        if (origActivity != null) {
-            proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
-        }
-        proto.write(ACTIVITY_TYPE, getActivityType());
-        proto.write(RESIZE_MODE, mResizeMode);
-        // TODO: Remove, no longer needed with windowingMode.
-        proto.write(FULLSCREEN, matchParentBounds());
-
-        if (!matchParentBounds()) {
-            final Rect bounds = getRequestedOverrideBounds();
-            bounds.writeToProto(proto, BOUNDS);
-        }
-        proto.write(MIN_WIDTH, mMinWidth);
-        proto.write(MIN_HEIGHT, mMinHeight);
-        proto.end(token);
-    }
-
-    /**
-     * See {@link #getNumRunningActivities(TaskActivitiesReport)}.
-     */
-    static class TaskActivitiesReport {
-        int numRunning;
-        int numActivities;
-        ActivityRecord top;
-        ActivityRecord base;
-
-        void reset() {
-            numRunning = numActivities = 0;
-            top = base = null;
-        }
-    }
-
-    /**
-     * Saves this {@link TaskRecord} to XML using given serializer.
-     */
-    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
-        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
-
-        out.attribute(null, ATTR_TASKID, String.valueOf(mTaskId));
-        if (realActivity != null) {
-            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
-        }
-        out.attribute(null, ATTR_REALACTIVITY_SUSPENDED, String.valueOf(realActivitySuspended));
-        if (origActivity != null) {
-            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
-        }
-        // Write affinity, and root affinity if it is different from affinity.
-        // We use the special string "@" for a null root affinity, so we can identify
-        // later whether we were given a root affinity or should just make it the
-        // same as the affinity.
-        if (affinity != null) {
-            out.attribute(null, ATTR_AFFINITY, affinity);
-            if (!affinity.equals(rootAffinity)) {
-                out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
-            }
-        } else if (rootAffinity != null) {
-            out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
-        }
-        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
-        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
-        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
-        out.attribute(null, ATTR_USERID, String.valueOf(mUserId));
-        out.attribute(null, ATTR_USER_SETUP_COMPLETE, String.valueOf(mUserSetupComplete));
-        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
-        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
-        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
-        if (lastDescription != null) {
-            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
-        }
-        if (getTaskDescription() != null) {
-            getTaskDescription().saveToXml(out);
-        }
-        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
-        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
-        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
-        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
-        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
-        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
-        out.attribute(null, ATTR_RESIZE_MODE, String.valueOf(mResizeMode));
-        out.attribute(null, ATTR_SUPPORTS_PICTURE_IN_PICTURE,
-                String.valueOf(mSupportsPictureInPicture));
-        if (mLastNonFullscreenBounds != null) {
-            out.attribute(
-                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
-        }
-        out.attribute(null, ATTR_MIN_WIDTH, String.valueOf(mMinWidth));
-        out.attribute(null, ATTR_MIN_HEIGHT, String.valueOf(mMinHeight));
-        out.attribute(null, ATTR_PERSIST_TASK_VERSION, String.valueOf(PERSIST_TASK_VERSION));
-
-        if (affinityIntent != null) {
-            out.startTag(null, TAG_AFFINITYINTENT);
-            affinityIntent.saveToXml(out);
-            out.endTag(null, TAG_AFFINITYINTENT);
-        }
-
-        if (intent != null) {
-            out.startTag(null, TAG_INTENT);
-            intent.saveToXml(out);
-            out.endTag(null, TAG_INTENT);
-        }
-
-        final int numActivities = getChildCount();
-        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
-            final ActivityRecord r = getChildAt(activityNdx);
-            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
-                    ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
-                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
-                            activityNdx > 0) {
-                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
-                break;
-            }
-            out.startTag(null, TAG_ACTIVITY);
-            r.saveToXml(out);
-            out.endTag(null, TAG_ACTIVITY);
-        }
-    }
-
-    @VisibleForTesting
-    static TaskRecordFactory getTaskRecordFactory() {
-        if (sTaskRecordFactory == null) {
-            setTaskRecordFactory(new TaskRecordFactory());
-        }
-        return sTaskRecordFactory;
-    }
-
-    static void setTaskRecordFactory(TaskRecordFactory factory) {
-        sTaskRecordFactory = factory;
-    }
-
-    static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-            Intent intent, IVoiceInteractionSession voiceSession,
-            IVoiceInteractor voiceInteractor, ActivityStack stack) {
-        return getTaskRecordFactory().create(
-                service, taskId, info, intent, voiceSession, voiceInteractor, stack);
-    }
-
-    static TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-            Intent intent, TaskDescription taskDescription, ActivityStack stack) {
-        return getTaskRecordFactory().create(service, taskId, info, intent, taskDescription, stack);
-    }
-
-    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
-            throws IOException, XmlPullParserException {
-        return getTaskRecordFactory().restoreFromXml(in, stackSupervisor);
-    }
-
-    /**
-     * A factory class used to create {@link TaskRecord} or its subclass if any. This can be
-     * specified when system boots by setting it with
-     * {@link #setTaskRecordFactory(TaskRecordFactory)}.
-     */
-    static class TaskRecordFactory {
-
-        TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent, IVoiceInteractionSession voiceSession,
-                IVoiceInteractor voiceInteractor, ActivityStack stack) {
-            return new TaskRecord(service, taskId, info, intent, voiceSession, voiceInteractor,
-                    null /*taskDescription*/, stack);
-        }
-
-        TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
-                Intent intent, TaskDescription taskDescription, ActivityStack stack) {
-            return new TaskRecord(service, taskId, info, intent, null /*voiceSession*/,
-                    null /*voiceInteractor*/, taskDescription, stack);
-        }
-
-        /**
-         * Should only be used when we're restoring {@link TaskRecord} from storage.
-         */
-        TaskRecord create(ActivityTaskManagerService service, int taskId, Intent intent,
-                Intent affinityIntent, String affinity, String rootAffinity,
-                ComponentName realActivity, ComponentName origActivity, boolean rootWasReset,
-                boolean autoRemoveRecents, boolean askedCompatMode, int userId,
-                int effectiveUid, String lastDescription,
-                long lastTimeMoved, boolean neverRelinquishIdentity,
-                TaskDescription lastTaskDescription, int taskAffiliation, int prevTaskId,
-                int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage,
-                int resizeMode, boolean supportsPictureInPicture, boolean realActivitySuspended,
-                boolean userSetupComplete, int minWidth, int minHeight, ActivityStack stack) {
-            return new TaskRecord(service, taskId, intent, affinityIntent, affinity,
-                    rootAffinity, realActivity, origActivity, rootWasReset, autoRemoveRecents,
-                    askedCompatMode, userId, effectiveUid, lastDescription,
-                    lastTimeMoved, neverRelinquishIdentity, lastTaskDescription, taskAffiliation,
-                    prevTaskId, nextTaskId, taskAffiliationColor, callingUid, callingPackage,
-                    resizeMode, supportsPictureInPicture, realActivitySuspended, userSetupComplete,
-                    minWidth, minHeight, null /*ActivityInfo*/, null /*_voiceSession*/,
-                    null /*_voiceInteractor*/, stack);
-        }
-
-        TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
-                throws IOException, XmlPullParserException {
-            Intent intent = null;
-            Intent affinityIntent = null;
-            ArrayList<ActivityRecord> activities = new ArrayList<>();
-            ComponentName realActivity = null;
-            boolean realActivitySuspended = false;
-            ComponentName origActivity = null;
-            String affinity = null;
-            String rootAffinity = null;
-            boolean hasRootAffinity = false;
-            boolean rootHasReset = false;
-            boolean autoRemoveRecents = false;
-            boolean askedCompatMode = false;
-            int taskType = 0;
-            int userId = 0;
-            boolean userSetupComplete = true;
-            int effectiveUid = -1;
-            String lastDescription = null;
-            long lastTimeOnTop = 0;
-            boolean neverRelinquishIdentity = true;
-            int taskId = INVALID_TASK_ID;
-            final int outerDepth = in.getDepth();
-            TaskDescription taskDescription = new TaskDescription();
-            int taskAffiliation = INVALID_TASK_ID;
-            int taskAffiliationColor = 0;
-            int prevTaskId = INVALID_TASK_ID;
-            int nextTaskId = INVALID_TASK_ID;
-            int callingUid = -1;
-            String callingPackage = "";
-            int resizeMode = RESIZE_MODE_FORCE_RESIZEABLE;
-            boolean supportsPictureInPicture = false;
-            Rect lastNonFullscreenBounds = null;
-            int minWidth = INVALID_MIN_SIZE;
-            int minHeight = INVALID_MIN_SIZE;
-            int persistTaskVersion = 0;
-
-            for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
-                final String attrName = in.getAttributeName(attrNdx);
-                final String attrValue = in.getAttributeValue(attrNdx);
-                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
-                        attrName + " value=" + attrValue);
-                switch (attrName) {
-                    case ATTR_TASKID:
-                        if (taskId == INVALID_TASK_ID) taskId = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_REALACTIVITY:
-                        realActivity = ComponentName.unflattenFromString(attrValue);
-                        break;
-                    case ATTR_REALACTIVITY_SUSPENDED:
-                        realActivitySuspended = Boolean.valueOf(attrValue);
-                        break;
-                    case ATTR_ORIGACTIVITY:
-                        origActivity = ComponentName.unflattenFromString(attrValue);
-                        break;
-                    case ATTR_AFFINITY:
-                        affinity = attrValue;
-                        break;
-                    case ATTR_ROOT_AFFINITY:
-                        rootAffinity = attrValue;
-                        hasRootAffinity = true;
-                        break;
-                    case ATTR_ROOTHASRESET:
-                        rootHasReset = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_AUTOREMOVERECENTS:
-                        autoRemoveRecents = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_ASKEDCOMPATMODE:
-                        askedCompatMode = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_USERID:
-                        userId = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_USER_SETUP_COMPLETE:
-                        userSetupComplete = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_EFFECTIVE_UID:
-                        effectiveUid = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_TASKTYPE:
-                        taskType = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_LASTDESCRIPTION:
-                        lastDescription = attrValue;
-                        break;
-                    case ATTR_LASTTIMEMOVED:
-                        lastTimeOnTop = Long.parseLong(attrValue);
-                        break;
-                    case ATTR_NEVERRELINQUISH:
-                        neverRelinquishIdentity = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_TASK_AFFILIATION:
-                        taskAffiliation = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_PREV_AFFILIATION:
-                        prevTaskId = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_NEXT_AFFILIATION:
-                        nextTaskId = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_TASK_AFFILIATION_COLOR:
-                        taskAffiliationColor = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_CALLING_UID:
-                        callingUid = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_CALLING_PACKAGE:
-                        callingPackage = attrValue;
-                        break;
-                    case ATTR_RESIZE_MODE:
-                        resizeMode = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_SUPPORTS_PICTURE_IN_PICTURE:
-                        supportsPictureInPicture = Boolean.parseBoolean(attrValue);
-                        break;
-                    case ATTR_NON_FULLSCREEN_BOUNDS:
-                        lastNonFullscreenBounds = Rect.unflattenFromString(attrValue);
-                        break;
-                    case ATTR_MIN_WIDTH:
-                        minWidth = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_MIN_HEIGHT:
-                        minHeight = Integer.parseInt(attrValue);
-                        break;
-                    case ATTR_PERSIST_TASK_VERSION:
-                        persistTaskVersion = Integer.parseInt(attrValue);
-                        break;
-                    default:
-                        if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
-                            taskDescription.restoreFromXml(attrName, attrValue);
-                        } else {
-                            Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
-                        }
-                }
-            }
-
-            int event;
-            while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
-                    (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
-                if (event == XmlPullParser.START_TAG) {
-                    final String name = in.getName();
-                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
-                            "TaskRecord: START_TAG name=" + name);
-                    if (TAG_AFFINITYINTENT.equals(name)) {
-                        affinityIntent = Intent.restoreFromXml(in);
-                    } else if (TAG_INTENT.equals(name)) {
-                        intent = Intent.restoreFromXml(in);
-                    } else if (TAG_ACTIVITY.equals(name)) {
-                        ActivityRecord activity =
-                                ActivityRecord.restoreFromXml(in, stackSupervisor);
-                        if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
-                                activity);
-                        if (activity != null) {
-                            activities.add(activity);
-                        }
-                    } else {
-                        handleUnknownTag(name, in);
-                    }
-                }
-            }
-            if (!hasRootAffinity) {
-                rootAffinity = affinity;
-            } else if ("@".equals(rootAffinity)) {
-                rootAffinity = null;
-            }
-            if (effectiveUid <= 0) {
-                Intent checkIntent = intent != null ? intent : affinityIntent;
-                effectiveUid = 0;
-                if (checkIntent != null) {
-                    IPackageManager pm = AppGlobals.getPackageManager();
-                    try {
-                        ApplicationInfo ai = pm.getApplicationInfo(
-                                checkIntent.getComponent().getPackageName(),
-                                PackageManager.MATCH_UNINSTALLED_PACKAGES
-                                        | PackageManager.MATCH_DISABLED_COMPONENTS, userId);
-                        if (ai != null) {
-                            effectiveUid = ai.uid;
-                        }
-                    } catch (RemoteException e) {
-                    }
-                }
-                Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
-                        + ": effectiveUid=" + effectiveUid);
-            }
-
-            if (persistTaskVersion < 1) {
-                // We need to convert the resize mode of home activities saved before version one if
-                // they are marked as RESIZE_MODE_RESIZEABLE to
-                // RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION since we didn't have that differentiation
-                // before version 1 and the system didn't resize home activities before then.
-                if (taskType == 1 /* old home type */ && resizeMode == RESIZE_MODE_RESIZEABLE) {
-                    resizeMode = RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
-                }
-            } else {
-                // This activity has previously marked itself explicitly as both resizeable and
-                // supporting picture-in-picture.  Since there is no longer a requirement for
-                // picture-in-picture activities to be resizeable, we can mark this simply as
-                // resizeable and supporting picture-in-picture separately.
-                if (resizeMode == RESIZE_MODE_RESIZEABLE_AND_PIPABLE_DEPRECATED) {
-                    resizeMode = RESIZE_MODE_RESIZEABLE;
-                    supportsPictureInPicture = true;
-                }
-            }
-
-            final TaskRecord task = create(stackSupervisor.mService,
-                    taskId, intent, affinityIntent,
-                    affinity, rootAffinity, realActivity, origActivity, rootHasReset,
-                    autoRemoveRecents, askedCompatMode, userId, effectiveUid, lastDescription,
-                    lastTimeOnTop, neverRelinquishIdentity, taskDescription,
-                    taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, callingUid,
-                    callingPackage, resizeMode, supportsPictureInPicture, realActivitySuspended,
-                    userSetupComplete, minWidth, minHeight, null /*stack*/);
-            task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
-            task.setBounds(lastNonFullscreenBounds);
-
-            for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
-                task.addChild(activities.get(activityNdx));
-            }
-
-            if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
-            return task;
-        }
-
-        void handleUnknownTag(String name, XmlPullParser in)
-                throws IOException, XmlPullParserException {
-            Slog.e(TAG, "restoreTask: Unexpected name=" + name);
-            XmlUtils.skipCurrentTag(in);
-        }
-    }
-}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 0d4ec65..35f61a8 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
 import static com.android.server.wm.TaskSnapshotPersister.DISABLE_FULL_SIZED_BITMAPS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -248,6 +250,12 @@
     @Nullable
     SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
             float scaleFraction) {
+        return createTaskSnapshot(task, scaleFraction, PixelFormat.RGBA_8888);
+    }
+
+    @Nullable
+    SurfaceControl.ScreenshotGraphicBuffer createTaskSnapshot(@NonNull Task task,
+            float scaleFraction, int pixelFormat) {
         if (task.getSurfaceControl() == null) {
             if (DEBUG_SCREENSHOT) {
                 Slog.w(TAG_WM, "Failed to take screenshot. No surface control for " + task);
@@ -258,7 +266,7 @@
         mTmpRect.offsetTo(0, 0);
         final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
                 SurfaceControl.captureLayers(
-                        task.getSurfaceControl(), mTmpRect, scaleFraction);
+                        task.getSurfaceControl(), mTmpRect, scaleFraction, pixelFormat);
         final GraphicBuffer buffer = screenshotBuffer != null ? screenshotBuffer.getGraphicBuffer()
                 : null;
         if (buffer == null || buffer.getWidth() <= 1 || buffer.getHeight() <= 1) {
@@ -299,8 +307,14 @@
             Slog.w(TAG_WM, "Failed to take screenshot. No main window for " + task);
             return null;
         }
+        final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
+        final boolean isShowWallpaper = (mainWindow.getAttrs().flags & FLAG_SHOW_WALLPAPER) != 0;
+        final int pixelFormat = mPersister.use16BitFormat() && activity.fillsParent()
+                && !(isWindowTranslucent && isShowWallpaper)
+                ? PixelFormat.RGB_565
+                : PixelFormat.RGBA_8888;
         final SurfaceControl.ScreenshotGraphicBuffer screenshotBuffer =
-                createTaskSnapshot(task, scaleFraction);
+                createTaskSnapshot(task, scaleFraction, pixelFormat);
 
         if (screenshotBuffer == null) {
             if (DEBUG_SCREENSHOT) {
@@ -308,7 +322,8 @@
             }
             return null;
         }
-        final boolean isWindowTranslucent = mainWindow.getAttrs().format != PixelFormat.OPAQUE;
+        final boolean isTranslucent = PixelFormat.formatHasAlpha(pixelFormat)
+                && (!activity.fillsParent() || isWindowTranslucent);
         return new TaskSnapshot(
                 System.currentTimeMillis() /* id */,
                 activity.mActivityComponent, screenshotBuffer.getGraphicBuffer(),
@@ -316,7 +331,7 @@
                 activity.getTask().getConfiguration().orientation,
                 getInsets(mainWindow), isLowRamDevice /* reduced */, scaleFraction /* scale */,
                 true /* isRealSnapshot */, task.getWindowingMode(), getSystemUiVisibility(task),
-                !activity.fillsParent() || isWindowTranslucent);
+                isTranslucent);
     }
 
     private boolean shouldDisableSnapshots() {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
index 696e1c3..22c1ea5 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotLoader.java
@@ -75,25 +75,35 @@
             final byte[] bytes = Files.readAllBytes(protoFile.toPath());
             final TaskSnapshotProto proto = TaskSnapshotProto.parseFrom(bytes);
             final Options options = new Options();
-            options.inPreferredConfig = Config.HARDWARE;
+            options.inPreferredConfig = mPersister.use16BitFormat() && !proto.isTranslucent
+                    ? Config.RGB_565
+                    : Config.ARGB_8888;
             final Bitmap bitmap = BitmapFactory.decodeFile(bitmapFile.getPath(), options);
             if (bitmap == null) {
                 Slog.w(TAG, "Failed to load bitmap: " + bitmapFile.getPath());
                 return null;
             }
-            final GraphicBuffer buffer = bitmap.createGraphicBufferHandle();
+
+            final Bitmap hwBitmap = bitmap.copy(Config.HARDWARE, false);
+            bitmap.recycle();
+            if (hwBitmap == null) {
+                Slog.w(TAG, "Failed to create hardware bitmap: " + bitmapFile.getPath());
+                return null;
+            }
+            final GraphicBuffer buffer = hwBitmap.createGraphicBufferHandle();
             if (buffer == null) {
                 Slog.w(TAG, "Failed to retrieve gralloc buffer for bitmap: "
                         + bitmapFile.getPath());
                 return null;
             }
+
             final ComponentName topActivityComponent = ComponentName.unflattenFromString(
                     proto.topActivityComponent);
             // For legacy snapshots, restore the scale based on the reduced resolution state
             final float legacyScale = reducedResolution ? mPersister.getReducedScale() : 1f;
             final float scale = Float.compare(proto.scale, 0f) != 0 ? proto.scale : legacyScale;
-            return new TaskSnapshot(proto.id, topActivityComponent, buffer, bitmap.getColorSpace(),
-                    proto.orientation,
+            return new TaskSnapshot(proto.id, topActivityComponent, buffer,
+                    hwBitmap.getColorSpace(), proto.orientation,
                     new Rect(proto.insetLeft, proto.insetTop, proto.insetRight, proto.insetBottom),
                     reducedResolution, scale, proto.isRealSnapshot, proto.windowingMode,
                     proto.systemUiVisibility, proto.isTranslucent);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index a156f5c..5915590 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -74,6 +74,7 @@
     private final Object mLock = new Object();
     private final DirectoryResolver mDirectoryResolver;
     private final float mReducedScale;
+    private final boolean mUse16BitFormat;
 
     /**
      * The list of ids of the tasks that have been persisted since {@link #removeObsoleteFiles} was
@@ -92,6 +93,8 @@
             mReducedScale = ActivityManager.isLowRamDeviceStatic()
                     ? LOW_RAM_REDUCED_SCALE : REDUCED_SCALE;
         }
+        mUse16BitFormat = service.mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_use16BitTaskSnapshotPixelFormat);
     }
 
     /**
@@ -164,6 +167,15 @@
         return mReducedScale;
     }
 
+    /**
+     * Return if task snapshots are stored in 16 bit pixel format.
+     *
+     * @return true if task snapshots are stored in 16 bit pixel format.
+     */
+    boolean use16BitFormat() {
+        return mUse16BitFormat;
+    }
+
     @TestApi
     void waitForQueueEmpty() {
         while (true) {
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/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
deleted file mode 100644
index 95a908f..0000000
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ /dev/null
@@ -1,1876 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT;
-import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.PINNED_WINDOWING_MODE_ELEVATION_IN_DIP;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.DOCKED_BOTTOM;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.DOCKED_LEFT;
-import static android.view.WindowManager.DOCKED_RIGHT;
-import static android.view.WindowManager.DOCKED_TOP;
-
-import static com.android.server.wm.BoundsAnimationController.FADE_IN;
-import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
-import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
-import static com.android.server.wm.BoundsAnimationController.SchedulePipModeChangedState;
-import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
-import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
-import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
-import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT;
-import static com.android.server.wm.StackProto.ANIMATING_BOUNDS;
-import static com.android.server.wm.StackProto.BOUNDS;
-import static com.android.server.wm.StackProto.DEFER_REMOVAL;
-import static com.android.server.wm.StackProto.FILLS_PARENT;
-import static com.android.server.wm.StackProto.ID;
-import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
-import static com.android.server.wm.StackProto.TASKS;
-import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
-import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
-import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
-import android.annotation.CallSuper;
-import android.app.RemoteAction;
-import android.content.res.Configuration;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.Region;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.EventLog;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-import android.view.DisplayCutout;
-import android.view.DisplayInfo;
-import android.view.RemoteAnimationTarget;
-import android.view.SurfaceControl;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.DividerSnapAlgorithm;
-import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
-import com.android.internal.policy.DockedDividerUtils;
-import com.android.server.EventLogTags;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
-
-public class TaskStack extends WindowContainer<TaskRecord> implements
-        BoundsAnimationTarget, ConfigurationContainerListener {
-    /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
-     * restrict IME adjustment so that a min portion of top stack remains visible.*/
-    private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
-
-    /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
-    private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
-
-    /** Unique identifier */
-    final int mStackId;
-
-    /** For comparison with DisplayContent bounds. */
-    private Rect mTmpRect = new Rect();
-    private Rect mTmpRect2 = new Rect();
-    private Rect mTmpRect3 = new Rect();
-
-    /** For Pinned stack controlling. */
-    private Rect mTmpToBounds = new Rect();
-
-    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
-    private final Rect mAdjustedBounds = new Rect();
-
-    /**
-     * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
-     * represent the state when the animation has ended.
-     */
-    private final Rect mFullyAdjustedImeBounds = new Rect();
-
-    /** ActivityRecords that are exiting, but still on screen for animations. */
-    final ArrayList<ActivityRecord> mExitingActivities = new ArrayList<>();
-
-    /** Detach this stack from its display when animation completes. */
-    // TODO: maybe tie this to WindowContainer#removeChild some how...
-    boolean mDeferRemoval;
-
-    private final Rect mTmpAdjustedBounds = new Rect();
-    private boolean mAdjustedForIme;
-    private boolean mImeGoingAway;
-    private WindowState mImeWin;
-    private float mMinimizeAmount;
-    private float mAdjustImeAmount;
-    private float mAdjustDividerAmount;
-    private final int mDockedStackMinimizeThickness;
-
-    // If this is true, we are in the bounds animating mode. The task will be down or upscaled to
-    // perfectly fit the region it would have been cropped to. We may also avoid certain logic we
-    // would otherwise apply while resizing, while resizing in the bounds animating mode.
-    private boolean mBoundsAnimating = false;
-    // Set when an animation has been requested but has not yet started from the UI thread. This is
-    // cleared when the animation actually starts.
-    private boolean mBoundsAnimatingRequested = false;
-    private boolean mBoundsAnimatingToFullscreen = false;
-    private boolean mCancelCurrentBoundsAnimation = false;
-    private Rect mBoundsAnimationTarget = new Rect();
-    private Rect mBoundsAnimationSourceHintBounds = new Rect();
-    private @BoundsAnimationController.AnimationType int mAnimationType;
-
-    Rect mPreAnimationBounds = new Rect();
-
-    private Dimmer mDimmer = new Dimmer(this);
-
-    // TODO: remove after unification.
-    ActivityStack mActivityStack;
-
-    /**
-     * For {@link #prepareSurfaces}.
-     */
-    final Rect mTmpDimBoundsRect = new Rect();
-    private final Point mLastSurfaceSize = new Point();
-
-    private final AnimatingActivityRegistry mAnimatingActivityRegistry =
-            new AnimatingActivityRegistry();
-
-    TaskStack(WindowManagerService service, int stackId, ActivityStack activityStack) {
-        super(service);
-        mStackId = stackId;
-        mActivityStack = activityStack;
-        activityStack.registerConfigurationChangeListener(this);
-        mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.docked_stack_minimize_thickness);
-        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
-    }
-
-    Task findHomeTask() {
-        if (!isActivityTypeHome() || mChildren.isEmpty()) {
-            return null;
-        }
-        return mChildren.get(mChildren.size() - 1);
-    }
-
-    void prepareFreezingTaskBounds() {
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mChildren.get(taskNdx);
-            task.prepareFreezingBounds();
-        }
-    }
-
-    /**
-     * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
-     * the normal task bounds.
-     *
-     * @param bounds The adjusted bounds.
-     */
-    private void setAdjustedBounds(Rect bounds) {
-        if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
-            return;
-        }
-
-        mAdjustedBounds.set(bounds);
-        final boolean adjusted = !mAdjustedBounds.isEmpty();
-        Rect insetBounds = null;
-        if (adjusted && isAdjustedForMinimizedDockedStack()) {
-            insetBounds = getRawBounds();
-        } else if (adjusted && mAdjustedForIme) {
-            if (mImeGoingAway) {
-                insetBounds = getRawBounds();
-            } else {
-                insetBounds = mFullyAdjustedImeBounds;
-            }
-        }
-        alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : getRawBounds(), insetBounds);
-        mDisplayContent.setLayoutNeeded();
-
-        updateSurfaceBounds();
-    }
-
-    private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
-        if (matchParentBounds()) {
-            return;
-        }
-
-        final boolean alignBottom = mAdjustedForIme && getDockSide() == DOCKED_TOP;
-
-        // Update bounds of containing tasks.
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; --taskNdx) {
-            final Task task = mChildren.get(taskNdx);
-            task.alignToAdjustedBounds(adjustedBounds, tempInsetBounds, alignBottom);
-        }
-    }
-
-    @Override
-    public int setBounds(Rect bounds) {
-        return setBounds(getRequestedOverrideBounds(), bounds);
-    }
-
-    private int setBounds(Rect existing, Rect bounds) {
-        if (equivalentBounds(existing, bounds)) {
-            return BOUNDS_CHANGE_NONE;
-        }
-
-        final int result = super.setBounds(bounds);
-
-        updateAdjustedBounds();
-
-        updateSurfaceBounds();
-        return result;
-    }
-
-    /** Bounds of the stack without adjusting for other factors in the system like visibility
-     * of docked stack.
-     * Most callers should be using {@link ConfigurationContainer#getRequestedOverrideBounds} a
-     * it takes into consideration other system factors. */
-    void getRawBounds(Rect out) {
-        out.set(getRawBounds());
-    }
-
-    Rect getRawBounds() {
-        return super.getBounds();
-    }
-
-    @Override
-    public void getBounds(Rect bounds) {
-        bounds.set(getBounds());
-    }
-
-    @Override
-    public Rect getBounds() {
-        // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
-        // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
-        // stack is visible since it is already what we want to represent to the rest of the
-        // system.
-        if (!mAdjustedBounds.isEmpty()) {
-            return mAdjustedBounds;
-        } else {
-            return super.getBounds();
-        }
-    }
-
-    /**
-     * Sets the bounds animation target bounds ahead of an animation.  This can't currently be done
-     * in onAnimationStart() since that is started on the UiThread.
-     */
-    private void setAnimationFinalBounds(Rect sourceHintBounds, Rect destBounds,
-            boolean toFullscreen) {
-        if (mAnimationType == BoundsAnimationController.BOUNDS) {
-            mBoundsAnimatingRequested = true;
-        }
-        mBoundsAnimatingToFullscreen = toFullscreen;
-        if (destBounds != null) {
-            mBoundsAnimationTarget.set(destBounds);
-        } else {
-            mBoundsAnimationTarget.setEmpty();
-        }
-        if (sourceHintBounds != null) {
-            mBoundsAnimationSourceHintBounds.set(sourceHintBounds);
-        } else if (!mBoundsAnimating) {
-            // If the bounds are already animating, we don't want to reset the source hint. This is
-            // because the source hint is sent when starting the animation from the client that
-            // requested to enter pip. Other requests can adjust the pip bounds during an animation,
-            // but could accidentally reset the source hint bounds.
-            mBoundsAnimationSourceHintBounds.setEmpty();
-        }
-
-        mPreAnimationBounds.set(getRawBounds());
-    }
-
-    /**
-     * @return the final bounds for the bounds animation.
-     */
-    void getFinalAnimationBounds(Rect outBounds) {
-        outBounds.set(mBoundsAnimationTarget);
-    }
-
-    /**
-     * @return the final source bounds for the bounds animation.
-     */
-    void getFinalAnimationSourceHintBounds(Rect outBounds) {
-        outBounds.set(mBoundsAnimationSourceHintBounds);
-    }
-
-    /**
-     * @return the final animation bounds if the task stack is currently being animated, or the
-     *         current stack bounds otherwise.
-     */
-    void getAnimationOrCurrentBounds(Rect outBounds) {
-        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
-            getFinalAnimationBounds(outBounds);
-            return;
-        }
-        getBounds(outBounds);
-    }
-
-    /** Bounds of the stack with other system factors taken into consideration. */
-    void getDimBounds(Rect out) {
-        getBounds(out);
-    }
-
-    /**
-     * Updates the passed-in {@code inOutBounds} based on the current state of the
-     * pinned controller. This gets run *after* the override configuration is updated, so it's
-     * safe to rely on the controller's state in here (though eventually this dependence should
-     * be removed).
-     *
-     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
-     * update pinned controller state.
-     *
-     * @param inOutBounds the bounds to update (both input and output).
-     * @return true if bounds were updated to some non-empty value.
-     */
-    boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
-        boolean animating = false;
-        if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
-            animating = true;
-            getFinalAnimationBounds(mTmpRect2);
-        } else {
-            mTmpRect2.set(inOutBounds);
-        }
-        boolean updated = mDisplayContent.mPinnedStackControllerLocked.onTaskStackBoundsChanged(
-                mTmpRect2, mTmpRect3);
-        if (updated) {
-            inOutBounds.set(mTmpRect3);
-
-            // The final boundary is updated while there is an existing boundary animation. Let's
-            // cancel this animation to prevent the obsolete animation overwritten updated bounds.
-            if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
-                final DisplayContent displayContent = getDisplayContent();
-                displayContent.mBoundsAnimationController.getHandler().post(() ->
-                        displayContent.mBoundsAnimationController.cancel(this));
-            }
-            // Once we've set the bounds based on the rotation of the old bounds in the new
-            // orientation, clear the animation target bounds since they are obsolete, and
-            // cancel any currently running animations
-            mBoundsAnimationTarget.setEmpty();
-            mBoundsAnimationSourceHintBounds.setEmpty();
-            mCancelCurrentBoundsAnimation = true;
-        }
-        return updated;
-    }
-
-    /**
-     * Updates the passed-in {@code inOutBounds} based on the current state of the
-     * docked controller. This gets run *after* the override configuration is updated, so it's
-     * safe to rely on the controller's state in here (though eventually this dependence should
-     * be removed).
-     *
-     * This does NOT modify this TaskStack's configuration. However, it does, for the time-being,
-     * update docked controller state.
-     *
-     * @param parentConfig the parent configuration for reference.
-     * @param inOutBounds the bounds to update (both input and output).
-     */
-    void calculateDockedBoundsForConfigChange(Configuration parentConfig, Rect inOutBounds) {
-        final boolean primary =
-                getRequestedOverrideWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-        repositionSplitScreenStackAfterRotation(parentConfig, primary, inOutBounds);
-        final DisplayCutout cutout = mDisplayContent.getDisplayInfo().displayCutout;
-        snapDockedStackAfterRotation(parentConfig, cutout, inOutBounds);
-        if (primary) {
-            final int newDockSide = getDockSide(parentConfig, inOutBounds);
-            // Update the dock create mode and clear the dock create bounds, these
-            // might change after a rotation and the original values will be invalid.
-            mWmService.setDockedStackCreateStateLocked(
-                    (newDockSide == DOCKED_LEFT || newDockSide == DOCKED_TOP)
-                            ? SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT
-                            : SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT,
-                    null);
-            mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
-        }
-    }
-
-    /**
-     * Some primary split screen sides are not allowed by the policy. This method queries the policy
-     * and moves the primary stack around if needed.
-     *
-     * @param parentConfig the configuration of the stack's parent.
-     * @param primary true if adjusting the primary docked stack, false for secondary.
-     * @param inOutBounds the bounds of the stack to adjust.
-     */
-    void repositionSplitScreenStackAfterRotation(Configuration parentConfig, boolean primary,
-            Rect inOutBounds) {
-        final int dockSide = getDockSide(mDisplayContent, parentConfig, inOutBounds);
-        final int otherDockSide = DockedDividerUtils.invertDockSide(dockSide);
-        final int primaryDockSide = primary ? dockSide : otherDockSide;
-        if (mDisplayContent.getDockedDividerController()
-                .canPrimaryStackDockTo(primaryDockSide,
-                        parentConfig.windowConfiguration.getBounds(),
-                        parentConfig.windowConfiguration.getRotation())) {
-            return;
-        }
-        final Rect parentBounds = parentConfig.windowConfiguration.getBounds();
-        switch (otherDockSide) {
-            case DOCKED_LEFT:
-                int movement = inOutBounds.left;
-                inOutBounds.left -= movement;
-                inOutBounds.right -= movement;
-                break;
-            case DOCKED_RIGHT:
-                movement = parentBounds.right - inOutBounds.right;
-                inOutBounds.left += movement;
-                inOutBounds.right += movement;
-                break;
-            case DOCKED_TOP:
-                movement = inOutBounds.top;
-                inOutBounds.top -= movement;
-                inOutBounds.bottom -= movement;
-                break;
-            case DOCKED_BOTTOM:
-                movement = parentBounds.bottom - inOutBounds.bottom;
-                inOutBounds.top += movement;
-                inOutBounds.bottom += movement;
-                break;
-        }
-    }
-
-    /**
-     * Snaps the bounds after rotation to the closest snap target for the docked stack.
-     */
-    void snapDockedStackAfterRotation(Configuration parentConfig, DisplayCutout displayCutout,
-            Rect outBounds) {
-
-        // Calculate the current position.
-        final int dividerSize = mDisplayContent.getDockedDividerController().getContentWidth();
-        final int dockSide = getDockSide(parentConfig, outBounds);
-        final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
-                dockSide, dividerSize);
-        final int displayWidth = parentConfig.windowConfiguration.getBounds().width();
-        final int displayHeight = parentConfig.windowConfiguration.getBounds().height();
-
-        // Snap the position to a target.
-        final int rotation = parentConfig.windowConfiguration.getRotation();
-        final int orientation = parentConfig.orientation;
-        mDisplayContent.getDisplayPolicy().getStableInsetsLw(rotation, displayWidth, displayHeight,
-                displayCutout, outBounds);
-        final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
-                mWmService.mContext.getResources(), displayWidth, displayHeight,
-                dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
-                getDockSide(), isMinimizedDockAndHomeStackResizable());
-        final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
-
-        // Recalculate the bounds based on the position of the target.
-        DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
-                outBounds, displayWidth, displayHeight,
-                dividerSize);
-    }
-
-    /**
-     * Put a Task in this stack. Used for adding only.
-     * When task is added to top of the stack, the entire branch of the hierarchy (including stack
-     * and display) will be brought to top.
-     * @param task The task to add.
-     * @param position Target position to add the task to.
-     * @param showForAllUsers Whether to show the task regardless of the current user.
-     */
-    void addChild(TaskRecord task, int position, boolean showForAllUsers, boolean moveParents) {
-        // Add child task.
-        addChild(task, null);
-
-        // Move child to a proper position, as some restriction for position might apply.
-        position = positionChildAt(
-                position, task, moveParents /* includingParents */, showForAllUsers);
-        mActivityStack.onChildAdded(task, position);
-    }
-
-    @Override
-    void addChild(TaskRecord task, int position) {
-        addChild(task, position, task.showForAllUsers(), false /* includingParents */);
-    }
-
-    void positionChildAt(Task child, int position) {
-        if (DEBUG_STACK) {
-            Slog.i(TAG_WM, "positionChildAt: positioning task=" + child + " at " + position);
-        }
-        if (child == null) {
-            if (DEBUG_STACK) {
-                Slog.i(TAG_WM, "positionChildAt: could not find task=" + this);
-            }
-            return;
-        }
-        child.positionAt(position);
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtTop(TaskRecord child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        positionChildAt(POSITION_TOP, child, includingParents);
-
-        final DisplayContent displayContent = getDisplayContent();
-        if (displayContent.mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(false);
-        }
-        displayContent.layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    void positionChildAtBottom(TaskRecord child, boolean includingParents) {
-        if (child == null) {
-            // TODO: Fix the call-points that cause this to happen.
-            return;
-        }
-
-        positionChildAt(POSITION_BOTTOM, child, includingParents);
-
-        if (getDisplayContent().mAppTransition.isTransitionSet()) {
-            child.setSendingToBottom(true);
-        }
-        getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
-    }
-
-    @Override
-    void positionChildAt(int position, TaskRecord child, boolean includingParents) {
-        positionChildAt(position, child, includingParents, child.showForAllUsers());
-    }
-
-    /**
-     * Overridden version of {@link TaskStack#positionChildAt(int, Task, boolean)}. Used in
-     * {@link TaskStack#addChild(Task, int, boolean showForAllUsers, boolean)}, as it can receive
-     * showForAllUsers param from {@link ActivityRecord} instead of {@link Task#showForAllUsers()}.
-     */
-    int positionChildAt(int position, TaskRecord child, boolean includingParents,
-            boolean showForAllUsers) {
-        final int targetPosition = findPositionForTask(child, position, showForAllUsers);
-        super.positionChildAt(targetPosition, child, includingParents);
-
-        // Log positioning.
-        if (DEBUG_TASK_MOVEMENT)
-            Slog.d(TAG_WM, "positionTask: task=" + this + " position=" + position);
-
-        final int toTop = targetPosition == mChildren.size() - 1 ? 1 : 0;
-        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, child.mTaskId, toTop, targetPosition);
-
-        return targetPosition;
-    }
-
-    @Override
-    void onChildPositionChanged(WindowContainer child) {
-        // TODO(task-merge): Read comment on updateTaskMovement method.
-        //((TaskRecord) child).updateTaskMovement(true);
-    }
-
-    void reparent(int displayId, Rect outStackBounds, boolean onTop) {
-        final DisplayContent targetDc = mWmService.mRoot.getDisplayContent(displayId);
-        if (targetDc == null) {
-            throw new IllegalArgumentException("Trying to move stackId=" + mStackId
-                    + " to unknown displayId=" + displayId);
-        }
-
-        targetDc.moveStackToDisplay(this, onTop);
-        if (matchParentBounds()) {
-            outStackBounds.setEmpty();
-        } else {
-            getRawBounds(outStackBounds);
-        }
-    }
-
-    // TODO: We should really have users as a window container in the hierarchy so that we don't
-    // have to do complicated things like we are doing in this method.
-    private int findPositionForTask(Task task, int targetPosition, boolean showForAllUsers) {
-        final boolean canShowTask =
-                showForAllUsers || mWmService.isCurrentProfileLocked(task.mUserId);
-
-        final int stackSize = mChildren.size();
-        int minPosition = 0;
-        int maxPosition = stackSize - 1;
-
-        if (canShowTask) {
-            minPosition = computeMinPosition(minPosition, stackSize);
-        } else {
-            maxPosition = computeMaxPosition(maxPosition);
-        }
-
-        // preserve POSITION_BOTTOM/POSITION_TOP positions if they are still valid.
-        if (targetPosition == POSITION_BOTTOM && minPosition == 0) {
-            return POSITION_BOTTOM;
-        } else if (targetPosition == POSITION_TOP && maxPosition == (stackSize - 1)) {
-            return POSITION_TOP;
-        }
-        // Reset position based on minimum/maximum possible positions.
-        return Math.min(Math.max(targetPosition, minPosition), maxPosition);
-    }
-
-    /** Calculate the minimum possible position for a task that can be shown to the user.
-     *  The minimum position will be above all other tasks that can't be shown.
-     *  @param minPosition The minimum position the caller is suggesting.
-     *                  We will start adjusting up from here.
-     *  @param size The size of the current task list.
-     */
-    private int computeMinPosition(int minPosition, int size) {
-        while (minPosition < size) {
-            final Task tmpTask = mChildren.get(minPosition);
-            final boolean canShowTmpTask =
-                    tmpTask.showForAllUsers()
-                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
-            if (canShowTmpTask) {
-                break;
-            }
-            minPosition++;
-        }
-        return minPosition;
-    }
-
-    /** Calculate the maximum possible position for a task that can't be shown to the user.
-     *  The maximum position will be below all other tasks that can be shown.
-     *  @param maxPosition The maximum position the caller is suggesting.
-     *                  We will start adjusting down from here.
-     */
-    private int computeMaxPosition(int maxPosition) {
-        while (maxPosition > 0) {
-            final Task tmpTask = mChildren.get(maxPosition);
-            final boolean canShowTmpTask =
-                    tmpTask.showForAllUsers()
-                            || mWmService.isCurrentProfileLocked(tmpTask.mUserId);
-            if (!canShowTmpTask) {
-                break;
-            }
-            maxPosition--;
-        }
-        return maxPosition;
-    }
-
-    /**
-     * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
-     * back.
-     * @param task The Task to delete.
-     */
-    @Override
-    void removeChild(TaskRecord task) {
-        if (!mChildren.contains(task)) {
-            // Not really in this stack anymore...
-            return;
-        }
-        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeChild: task=" + task);
-
-        super.removeChild(task);
-
-        mActivityStack.onChildRemoved(task, mDisplayContent);
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newParentConfig) {
-        final int prevWindowingMode = getWindowingMode();
-        super.onConfigurationChanged(newParentConfig);
-
-        // Only need to update surface size here since the super method will handle updating
-        // surface position.
-        updateSurfaceSize(getPendingTransaction());
-        final int windowingMode = getWindowingMode();
-
-        if (mDisplayContent == null) {
-            return;
-        }
-
-        if (prevWindowingMode != windowingMode) {
-            mDisplayContent.onStackWindowingModeChanged(this);
-
-            if (inSplitScreenSecondaryWindowingMode()) {
-                // When the stack is resized due to entering split screen secondary, offset the
-                // windows to compensate for the new stack position.
-                forAllWindows(w -> {
-                    w.mWinAnimator.setOffsetPositionForStackResize(true);
-                }, true);
-            }
-        }
-    }
-
-    private void updateSurfaceBounds() {
-        updateSurfaceSize(getPendingTransaction());
-        updateSurfacePosition();
-        scheduleAnimation();
-    }
-
-    /**
-     * Calculate an amount by which to expand the stack bounds in each direction.
-     * Used to make room for shadows in the pinned windowing mode.
-     */
-    int getStackOutset() {
-        DisplayContent displayContent = getDisplayContent();
-        if (inPinnedWindowingMode() && displayContent != null) {
-            final DisplayMetrics displayMetrics = displayContent.getDisplayMetrics();
-
-            // We multiply by two to match the client logic for converting view elevation
-            // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets}
-            return (int)Math.ceil(mWmService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP,
-                    displayMetrics) * 2);
-        }
-        return 0;
-    }
-
-    @Override
-    void getRelativeDisplayedPosition(Point outPos) {
-        super.getRelativeDisplayedPosition(outPos);
-        final int outset = getStackOutset();
-        outPos.x -= outset;
-        outPos.y -= outset;
-    }
-
-    private void updateSurfaceSize(SurfaceControl.Transaction transaction) {
-        if (mSurfaceControl == null) {
-            return;
-        }
-
-        final Rect stackBounds = getDisplayedBounds();
-        int width = stackBounds.width();
-        int height = stackBounds.height();
-
-        final int outset = getStackOutset();
-        width += 2*outset;
-        height += 2*outset;
-
-        if (width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
-            return;
-        }
-        transaction.setWindowCrop(mSurfaceControl, width, height);
-        mLastSurfaceSize.set(width, height);
-    }
-
-    @VisibleForTesting
-    Point getLastSurfaceSize() {
-        return mLastSurfaceSize;
-    }
-
-    @Override
-    void onDisplayChanged(DisplayContent dc) {
-        if (mDisplayContent != null && mDisplayContent != dc) {
-            throw new IllegalStateException("onDisplayChanged: Already attached");
-        }
-
-        super.onDisplayChanged(dc);
-
-        updateSurfaceBounds();
-    }
-
-    /**
-     * Determines the stack and task bounds of the other stack when in docked mode. The current task
-     * bounds is passed in but depending on the stack, the task and stack must match. Only in
-     * minimized mode with resizable launcher, the other stack ignores calculating the stack bounds
-     * and uses the task bounds passed in as the stack and task bounds, otherwise the stack bounds
-     * is calculated and is also used for its task bounds.
-     * If any of the out bounds are empty, it represents default bounds
-     *
-     * @param currentTempTaskBounds the current task bounds of the other stack
-     * @param outStackBounds the calculated stack bounds of the other stack
-     * @param outTempTaskBounds the calculated task bounds of the other stack
-     */
-    void getStackDockedModeBoundsLocked(Configuration parentConfig, Rect dockedBounds,
-            Rect currentTempTaskBounds, Rect outStackBounds, Rect outTempTaskBounds) {
-        outTempTaskBounds.setEmpty();
-
-        if (dockedBounds == null || dockedBounds.isEmpty()) {
-            // Calculate the primary docked bounds.
-            final boolean dockedOnTopOrLeft = mWmService.mDockedStackCreateMode
-                    == SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
-            getStackDockedModeBounds(parentConfig,
-                    true /* primary */, outStackBounds, dockedBounds,
-                    mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
-            return;
-        }
-        final int dockedSide = getDockSide(parentConfig, dockedBounds);
-
-        // When the home stack is resizable, should always have the same stack and task bounds
-        if (isActivityTypeHome()) {
-            final Task homeTask = findHomeTask();
-            if (homeTask == null || homeTask.isResizeable()) {
-                // Calculate the home stack bounds when in docked mode and the home stack is
-                // resizeable.
-                getDisplayContent().mDividerControllerLocked
-                        .getHomeStackBoundsInDockedMode(parentConfig,
-                                dockedSide, outStackBounds);
-            } else {
-                // Home stack isn't resizeable, so don't specify stack bounds.
-                outStackBounds.setEmpty();
-            }
-
-            outTempTaskBounds.set(outStackBounds);
-            return;
-        }
-
-        // When minimized state, the stack bounds for all non-home and docked stack bounds should
-        // match the passed task bounds
-        if (isMinimizedDockAndHomeStackResizable() && currentTempTaskBounds != null) {
-            outStackBounds.set(currentTempTaskBounds);
-            return;
-        }
-
-        if (dockedSide == DOCKED_INVALID) {
-            // Not sure how you got here...Only thing we can do is return current bounds.
-            Slog.e(TAG_WM, "Failed to get valid docked side for docked stack");
-            outStackBounds.set(getRawBounds());
-            return;
-        }
-
-        final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
-        getStackDockedModeBounds(parentConfig,
-                false /* primary */, outStackBounds, dockedBounds,
-                mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
-    }
-
-    /**
-     * Outputs the bounds a stack should be given the presence of a docked stack on the display.
-     * @param parentConfig The parent configuration.
-     * @param primary {@code true} if getting the primary stack bounds.
-     * @param outBounds Output bounds that should be used for the stack.
-     * @param dockedBounds Bounds of the docked stack.
-     * @param dockDividerWidth We need to know the width of the divider make to the output bounds
-     *                         close to the side of the dock.
-     * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
-     */
-    private void getStackDockedModeBounds(Configuration parentConfig, boolean primary,
-            Rect outBounds, Rect dockedBounds, int dockDividerWidth,
-            boolean dockOnTopOrLeft) {
-        final Rect displayRect = parentConfig.windowConfiguration.getBounds();
-        final boolean splitHorizontally = displayRect.width() > displayRect.height();
-
-        outBounds.set(displayRect);
-        if (primary) {
-            if (mWmService.mDockedStackCreateBounds != null) {
-                outBounds.set(mWmService.mDockedStackCreateBounds);
-                return;
-            }
-
-            // The initial bounds of the docked stack when it is created about half the screen space
-            // and its bounds can be adjusted after that. The bounds of all other stacks are
-            // adjusted to occupy whatever screen space the docked stack isn't occupying.
-            final DisplayCutout displayCutout = mDisplayContent.getDisplayInfo().displayCutout;
-            mDisplayContent.getDisplayPolicy().getStableInsetsLw(
-                    parentConfig.windowConfiguration.getRotation(),
-                    displayRect.width(), displayRect.height(), displayCutout, mTmpRect2);
-            final int position = new DividerSnapAlgorithm(mWmService.mContext.getResources(),
-                    displayRect.width(),
-                    displayRect.height(),
-                    dockDividerWidth,
-                    parentConfig.orientation == ORIENTATION_PORTRAIT,
-                    mTmpRect2).getMiddleTarget().position;
-
-            if (dockOnTopOrLeft) {
-                if (splitHorizontally) {
-                    outBounds.right = position;
-                } else {
-                    outBounds.bottom = position;
-                }
-            } else {
-                if (splitHorizontally) {
-                    outBounds.left = position + dockDividerWidth;
-                } else {
-                    outBounds.top = position + dockDividerWidth;
-                }
-            }
-            return;
-        }
-
-        // Other stacks occupy whatever space is left by the docked stack.
-        if (!dockOnTopOrLeft) {
-            if (splitHorizontally) {
-                outBounds.right = dockedBounds.left - dockDividerWidth;
-            } else {
-                outBounds.bottom = dockedBounds.top - dockDividerWidth;
-            }
-        } else {
-            if (splitHorizontally) {
-                outBounds.left = dockedBounds.right + dockDividerWidth;
-            } else {
-                outBounds.top = dockedBounds.bottom + dockDividerWidth;
-            }
-        }
-        DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
-    }
-
-    void resetDockedStackToMiddle() {
-        if (!inSplitScreenPrimaryWindowingMode()) {
-            throw new IllegalStateException("Not a docked stack=" + this);
-        }
-
-        mWmService.mDockedStackCreateBounds = null;
-
-        final Rect bounds = new Rect();
-        final Rect tempBounds = new Rect();
-        getStackDockedModeBoundsLocked(mDisplayContent.getConfiguration(), null /* dockedBounds */,
-                null /* currentTempTaskBounds */, bounds, tempBounds);
-        mActivityStack.mStackSupervisor.resizeDockedStackLocked(bounds, null /* tempTaskBounds */,
-                null /* tempTaskInsetBounds */, null /* tempOtherTaskBounds */,
-                null /* tempOtherTaskInsetBounds */, false /* preserveWindows */,
-                false /* deferResume */);
-    }
-
-    @Override
-    void removeIfPossible() {
-        if (isAnimating(TRANSITION | CHILDREN)) {
-            mDeferRemoval = true;
-            return;
-        }
-        removeImmediately();
-    }
-
-    @Override
-    void removeImmediately() {
-        if (mActivityStack != null) {
-            mActivityStack.unregisterConfigurationChangeListener(this);
-        }
-        super.removeImmediately();
-    }
-
-    @Override
-    void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) {
-        super.onParentChanged(newParent, oldParent);
-
-        if (getParent() != null || mDisplayContent == null) {
-            return;
-        }
-
-        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
-
-        mDisplayContent = null;
-        mWmService.mWindowPlacerLocked.requestTraversal();
-    }
-
-    // TODO: Should each user have there own stacks?
-    @Override
-    void switchUser() {
-        super.switchUser();
-        int top = mChildren.size();
-        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
-            TaskRecord task = mChildren.get(taskNdx);
-            if (mWmService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
-                mChildren.remove(taskNdx);
-                mChildren.add(task);
-                --top;
-            }
-        }
-    }
-
-    /**
-     * Adjusts the stack bounds if the IME is visible.
-     *
-     * @param imeWin The IME window.
-     * @param keepLastAmount Use {@code true} to keep the last adjusted amount from
-     *                       {@link DockedStackDividerController} for adjusting the stack bounds,
-     *                       Use {@code false} to reset adjusted amount as 0.
-     * @see #updateAdjustForIme(float, float, boolean)
-     */
-    void setAdjustedForIme(WindowState imeWin, boolean keepLastAmount) {
-        mImeWin = imeWin;
-        mImeGoingAway = false;
-        if (!mAdjustedForIme || keepLastAmount) {
-            mAdjustedForIme = true;
-            DockedStackDividerController controller = getDisplayContent().mDividerControllerLocked;
-            final float adjustImeAmount = keepLastAmount ? controller.mLastAnimationProgress : 0f;
-            final float adjustDividerAmount = keepLastAmount ? controller.mLastDividerProgress : 0f;
-            updateAdjustForIme(adjustImeAmount, adjustDividerAmount, true /* force */);
-        }
-    }
-
-    boolean isAdjustedForIme() {
-        return mAdjustedForIme;
-    }
-
-    boolean isAnimatingForIme() {
-        return mImeWin != null && mImeWin.isAnimatingLw();
-    }
-
-    /**
-     * Update the stack's bounds (crop or position) according to the IME window's
-     * current position. When IME window is animated, the bottom stack is animated
-     * together to track the IME window's current position, and the top stack is
-     * cropped as necessary.
-     *
-     * @return true if a traversal should be performed after the adjustment.
-     */
-    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
-        if (adjustAmount != mAdjustImeAmount
-                || adjustDividerAmount != mAdjustDividerAmount || force) {
-            mAdjustImeAmount = adjustAmount;
-            mAdjustDividerAmount = adjustDividerAmount;
-            updateAdjustedBounds();
-            return isVisible();
-        } else {
-            return false;
-        }
-    }
-
-    /**
-     * Resets the adjustment after it got adjusted for the IME.
-     * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
-     *                        animations; otherwise, set flag and animates the window away together
-     *                        with IME window.
-     */
-    void resetAdjustedForIme(boolean adjustBoundsNow) {
-        if (adjustBoundsNow) {
-            mImeWin = null;
-            mImeGoingAway = false;
-            mAdjustImeAmount = 0f;
-            mAdjustDividerAmount = 0f;
-            if (!mAdjustedForIme) {
-                return;
-            }
-            mAdjustedForIme = false;
-            updateAdjustedBounds();
-            mWmService.setResizeDimLayer(false, getWindowingMode(), 1.0f);
-        } else {
-            mImeGoingAway |= mAdjustedForIme;
-        }
-    }
-
-    /**
-     * Sets the amount how much we currently minimize our stack.
-     *
-     * @param minimizeAmount The amount, between 0 and 1.
-     * @return Whether the amount has changed and a layout is needed.
-     */
-    boolean setAdjustedForMinimizedDock(float minimizeAmount) {
-        if (minimizeAmount != mMinimizeAmount) {
-            mMinimizeAmount = minimizeAmount;
-            updateAdjustedBounds();
-            return isVisible();
-        } else {
-            return false;
-        }
-    }
-
-    boolean shouldIgnoreInput() {
-        return isAdjustedForMinimizedDockedStack() ||
-                (inSplitScreenPrimaryWindowingMode() && isMinimizedDockAndHomeStackResizable());
-    }
-
-    /**
-     * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
-     * to the list of to be drawn windows the service is waiting for.
-     */
-    void beginImeAdjustAnimation() {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final Task task = mChildren.get(j);
-            if (task.hasContentToDisplay()) {
-                task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-                task.setWaitingForDrawnIfResizingChanged();
-            }
-        }
-    }
-
-    /**
-     * Resets the resizing state of all windows.
-     */
-    void endImeAdjustAnimation() {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            mChildren.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
-        }
-    }
-
-    int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
-        return displayContentRect.top + (int)
-                ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
-    }
-
-    private boolean adjustForIME(final WindowState imeWin) {
-        // To prevent task stack resize animation may flicking when playing app transition
-        // animation & IME window enter animation in parallel, we need to make sure app
-        // transition is done and then adjust task size for IME, skip the new adjusted frame when
-        // app transition is still running.
-        if (getDisplayContent().mAppTransition.isRunning()) {
-            return false;
-        }
-
-        final int dockedSide = getDockSide();
-        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
-        if (imeWin == null || !dockedTopOrBottom) {
-            return false;
-        }
-
-        final Rect displayStableRect = mTmpRect;
-        final Rect contentBounds = mTmpRect2;
-
-        // Calculate the content bounds excluding the area occupied by IME
-        getDisplayContent().getStableRect(displayStableRect);
-        contentBounds.set(displayStableRect);
-        int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
-
-        imeTop += imeWin.getGivenContentInsetsLw().top;
-        if (contentBounds.bottom > imeTop) {
-            contentBounds.bottom = imeTop;
-        }
-
-        final int yOffset = displayStableRect.bottom - contentBounds.bottom;
-
-        final int dividerWidth =
-                getDisplayContent().mDividerControllerLocked.getContentWidth();
-        final int dividerWidthInactive =
-                getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
-
-        if (dockedSide == DOCKED_TOP) {
-            // If this stack is docked on top, we make it smaller so the bottom stack is not
-            // occluded by IME. We shift its bottom up by the height of the IME, but
-            // leaves at least 30% of the top stack visible.
-            final int minTopStackBottom =
-                    getMinTopStackBottom(displayStableRect, getRawBounds().bottom);
-            final int bottom = Math.max(
-                    getRawBounds().bottom - yOffset + dividerWidth - dividerWidthInactive,
-                    minTopStackBottom);
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.bottom = (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount)
-                    * getRawBounds().bottom);
-            mFullyAdjustedImeBounds.set(getRawBounds());
-        } else {
-            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
-            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
-
-            // When the stack is on bottom and has focus, it needs to be moved up so as to
-            // not occluded by IME, and at the same time adjusted for divider width.
-            // We try to move it up by the height of the IME window, but only to the extent
-            // that leaves at least 30% of the top stack visible.
-            // 'top' is where the top of bottom stack will move to in this case.
-            final int topBeforeImeAdjust =
-                    getRawBounds().top - dividerWidth + dividerWidthInactive;
-            final int minTopStackBottom =
-                    getMinTopStackBottom(displayStableRect,
-                            getRawBounds().top - dividerWidth);
-            final int top = Math.max(
-                    getRawBounds().top - yOffset, minTopStackBottom + dividerWidthInactive);
-
-            mTmpAdjustedBounds.set(getRawBounds());
-            // Account for the adjustment for IME and divider width separately.
-            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
-            // and dividerWidthDelta is due to divider width change only.
-            mTmpAdjustedBounds.top = getRawBounds().top +
-                    (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
-                            mAdjustDividerAmount * dividerWidthDelta);
-            mFullyAdjustedImeBounds.set(getRawBounds());
-            mFullyAdjustedImeBounds.top = top;
-            mFullyAdjustedImeBounds.bottom = top + getRawBounds().height();
-        }
-        return true;
-    }
-
-    private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
-        final int dockSide = getDockSide();
-        if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
-            return false;
-        }
-
-        if (dockSide == DOCKED_TOP) {
-            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
-            int topInset = mTmpRect.top;
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.bottom = (int) (minimizeAmount * topInset + (1 - minimizeAmount)
-                    * getRawBounds().bottom);
-        } else if (dockSide == DOCKED_LEFT) {
-            mTmpAdjustedBounds.set(getRawBounds());
-            final int width = getRawBounds().width();
-            mTmpAdjustedBounds.right =
-                    (int) (minimizeAmount * mDockedStackMinimizeThickness
-                            + (1 - minimizeAmount) * getRawBounds().right);
-            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
-        } else if (dockSide == DOCKED_RIGHT) {
-            mTmpAdjustedBounds.set(getRawBounds());
-            mTmpAdjustedBounds.left = (int) (minimizeAmount *
-                    (getRawBounds().right - mDockedStackMinimizeThickness)
-                            + (1 - minimizeAmount) * getRawBounds().left);
-        }
-        return true;
-    }
-
-    private boolean isMinimizedDockAndHomeStackResizable() {
-        return mDisplayContent.mDividerControllerLocked.isMinimizedDock()
-                && mDisplayContent.mDividerControllerLocked.isHomeStackResizable();
-    }
-
-    /**
-     * @return the distance in pixels how much the stack gets minimized from it's original size
-     */
-    int getMinimizeDistance() {
-        final int dockSide = getDockSide();
-        if (dockSide == DOCKED_INVALID) {
-            return 0;
-        }
-
-        if (dockSide == DOCKED_TOP) {
-            mWmService.getStableInsetsLocked(DEFAULT_DISPLAY, mTmpRect);
-            int topInset = mTmpRect.top;
-            return getRawBounds().bottom - topInset;
-        } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
-            return getRawBounds().width() - mDockedStackMinimizeThickness;
-        } else {
-            return 0;
-        }
-    }
-
-    /**
-     * Updates the adjustment depending on it's current state.
-     */
-    private void updateAdjustedBounds() {
-        boolean adjust = false;
-        if (mMinimizeAmount != 0f) {
-            adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
-        } else if (mAdjustedForIme) {
-            adjust = adjustForIME(mImeWin);
-        }
-        if (!adjust) {
-            mTmpAdjustedBounds.setEmpty();
-        }
-        setAdjustedBounds(mTmpAdjustedBounds);
-
-        final boolean isImeTarget = (mWmService.getImeFocusStackLocked() == this);
-        if (mAdjustedForIme && adjust && !isImeTarget) {
-            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
-                    * IME_ADJUST_DIM_AMOUNT;
-            mWmService.setResizeDimLayer(true, getWindowingMode(), alpha);
-        }
-    }
-
-    void applyAdjustForImeIfNeeded(Task task) {
-        if (mMinimizeAmount != 0f || !mAdjustedForIme || mAdjustedBounds.isEmpty()) {
-            return;
-        }
-
-        final Rect insetBounds = mImeGoingAway ? getRawBounds() : mFullyAdjustedImeBounds;
-        task.alignToAdjustedBounds(mAdjustedBounds, insetBounds, getDockSide() == DOCKED_TOP);
-        mDisplayContent.setLayoutNeeded();
-    }
-
-
-    boolean isAdjustedForMinimizedDockedStack() {
-        return mMinimizeAmount != 0f;
-    }
-
-    /**
-     * @return {@code true} if we have a {@link Task} that is animating (currently only used for the
-     *         recents animation); {@code false} otherwise.
-     */
-    boolean isTaskAnimating() {
-        for (int j = mChildren.size() - 1; j >= 0; j--) {
-            final Task task = mChildren.get(j);
-            if (task.isTaskAnimating()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @CallSuper
-    @Override
-    public void writeToProto(ProtoOutputStream proto, long fieldId,
-            @WindowTraceLogLevel int logLevel) {
-        if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
-            return;
-        }
-
-        final long token = proto.start(fieldId);
-        super.writeToProto(proto, WINDOW_CONTAINER, logLevel);
-        proto.write(ID, mStackId);
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).writeToProtoInnerTaskOnly(proto, TASKS, logLevel);
-        }
-        proto.write(FILLS_PARENT, matchParentBounds());
-        getRawBounds().writeToProto(proto, BOUNDS);
-        proto.write(DEFER_REMOVAL, mDeferRemoval);
-        proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
-        proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
-        proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
-        proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
-        mAdjustedBounds.writeToProto(proto, ADJUSTED_BOUNDS);
-        proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
-        proto.end(token);
-    }
-
-    @Override
-     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        pw.println(prefix + "mStackId=" + mStackId);
-        pw.println(prefix + "mDeferRemoval=" + mDeferRemoval);
-        pw.println(prefix + "mBounds=" + getRawBounds().toShortString());
-        if (mMinimizeAmount != 0f) {
-            pw.println(prefix + "mMinimizeAmount=" + mMinimizeAmount);
-        }
-        if (mAdjustedForIme) {
-            pw.println(prefix + "mAdjustedForIme=true");
-            pw.println(prefix + "mAdjustImeAmount=" + mAdjustImeAmount);
-            pw.println(prefix + "mAdjustDividerAmount=" + mAdjustDividerAmount);
-        }
-        if (!mAdjustedBounds.isEmpty()) {
-            pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
-        }
-        for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) {
-            mChildren.get(taskNdx).dump(pw, prefix + "  ", dumpAll);
-        }
-        if (!mExitingActivities.isEmpty()) {
-            pw.println();
-            pw.println("  Exiting application tokens:");
-            for (int i = mExitingActivities.size() - 1; i >= 0; i--) {
-                WindowToken token = mExitingActivities.get(i);
-                pw.print("  Exiting App #"); pw.print(i);
-                pw.print(' '); pw.print(token);
-                pw.println(':');
-                token.dump(pw, "    ", dumpAll);
-            }
-        }
-        mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix);
-    }
-
-    @Override
-    boolean fillsParent() {
-        return matchParentBounds();
-    }
-
-    @Override
-    public String toString() {
-        return "{stackId=" + mStackId + " tasks=" + mChildren + "}";
-    }
-
-    String getName() {
-        return toShortString();
-    }
-
-    public String toShortString() {
-        return "Stack=" + mStackId;
-    }
-
-    /**
-     * For docked workspace (or workspace that's side-by-side to the docked), provides
-     * information which side of the screen was the dock anchored.
-     */
-    int getDockSide() {
-        return getDockSide(mDisplayContent.getConfiguration(), getRawBounds());
-    }
-
-    int getDockSideForDisplay(DisplayContent dc) {
-        return getDockSide(dc, dc.getConfiguration(), getRawBounds());
-    }
-
-    int getDockSide(Configuration parentConfig, Rect bounds) {
-        if (mDisplayContent == null) {
-            return DOCKED_INVALID;
-        }
-        return getDockSide(mDisplayContent, parentConfig, bounds);
-    }
-
-    private int getDockSide(DisplayContent dc, Configuration parentConfig, Rect bounds) {
-        return dc.getDockedDividerController().getDockSide(bounds,
-                parentConfig.windowConfiguration.getBounds(),
-                parentConfig.orientation, parentConfig.windowConfiguration.getRotation());
-    }
-
-    boolean hasTaskForUser(int userId) {
-        for (int i = mChildren.size() - 1; i >= 0; i--) {
-            final Task task = mChildren.get(i);
-            if (task.mUserId == userId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void findTaskForResizePoint(int x, int y, int delta,
-            DisplayContent.TaskForResizePointSearchResult results) {
-        if (!getWindowConfiguration().canResizeTask()) {
-            results.searchDone = true;
-            return;
-        }
-
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task task = mChildren.get(i);
-            if (task.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
-                results.searchDone = true;
-                return;
-            }
-
-            // We need to use the task's dim bounds (which is derived from the visible bounds of
-            // its apps windows) for any touch-related tests. Can't use the task's original
-            // bounds because it might be adjusted to fit the content frame. One example is when
-            // the task is put to top-left quadrant, the actual visible area would not start at
-            // (0,0) after it's adjusted for the status bar.
-            task.getDimBounds(mTmpRect);
-            mTmpRect.inset(-delta, -delta);
-            if (mTmpRect.contains(x, y)) {
-                mTmpRect.inset(delta, delta);
-
-                results.searchDone = true;
-
-                if (!mTmpRect.contains(x, y)) {
-                    results.taskForResize = task;
-                    return;
-                }
-                // User touched inside the task. No need to look further,
-                // focus transfer will be handled in ACTION_UP.
-                return;
-            }
-        }
-    }
-
-    void setTouchExcludeRegion(Task focusedTask, int delta, Region touchExcludeRegion,
-            Rect contentRect, Rect postExclude) {
-        for (int i = mChildren.size() - 1; i >= 0; --i) {
-            final Task task = mChildren.get(i);
-            ActivityRecord topVisibleActivity = task.getTopVisibleActivity();
-            if (topVisibleActivity == null || !topVisibleActivity.hasContentToDisplay()) {
-                continue;
-            }
-
-            /**
-             * Exclusion region is the region that TapDetector doesn't care about.
-             * Here we want to remove all non-focused tasks from the exclusion region.
-             * We also remove the outside touch area for resizing for all freeform
-             * tasks (including the focused).
-             *
-             * We save the focused task region once we find it, and add it back at the end.
-             *
-             * If the task is home stack and it is resizable in the minimized state, we want to
-             * exclude the docked stack from touch so we need the entire screen area and not just a
-             * small portion which the home stack currently is resized to.
-             */
-
-            if (task.isActivityTypeHome() && isMinimizedDockAndHomeStackResizable()) {
-                mDisplayContent.getBounds(mTmpRect);
-            } else {
-                task.getDimBounds(mTmpRect);
-            }
-
-            if (task == focusedTask) {
-                // Add the focused task rect back into the exclude region once we are done
-                // processing stacks.
-                postExclude.set(mTmpRect);
-            }
-
-            final boolean isFreeformed = task.inFreeformWindowingMode();
-            if (task != focusedTask || isFreeformed) {
-                if (isFreeformed) {
-                    // If the task is freeformed, enlarge the area to account for outside
-                    // touch area for resize.
-                    mTmpRect.inset(-delta, -delta);
-                    // Intersect with display content rect. If we have system decor (status bar/
-                    // navigation bar), we want to exclude that from the tap detection.
-                    // Otherwise, if the app is partially placed under some system button (eg.
-                    // Recents, Home), pressing that button would cause a full series of
-                    // unwanted transfer focus/resume/pause, before we could go home.
-                    mTmpRect.intersect(contentRect);
-                }
-                touchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
-            }
-        }
-    }
-
-    public boolean setPinnedStackSize(Rect stackBounds, Rect tempTaskBounds) {
-        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
-        synchronized (mWmService.mGlobalLock) {
-            if (mCancelCurrentBoundsAnimation) {
-                return false;
-            }
-        }
-
-        try {
-            mWmService.mActivityTaskManager.resizePinnedStack(stackBounds, tempTaskBounds);
-        } catch (RemoteException e) {
-            // I don't believe you.
-        }
-        return true;
-    }
-
-    void onAllWindowsDrawn() {
-        if (!mBoundsAnimating && !mBoundsAnimatingRequested) {
-            return;
-        }
-
-        getDisplayContent().mBoundsAnimationController.onAllWindowsDrawn();
-    }
-
-    @Override  // AnimatesBounds
-    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
-            @BoundsAnimationController.AnimationType int animationType) {
-        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
-        synchronized (mWmService.mGlobalLock) {
-            if (!isAttached()) {
-                // Don't run the animation if the stack is already detached
-                return false;
-            }
-
-            if (animationType == BoundsAnimationController.BOUNDS) {
-                mBoundsAnimatingRequested = false;
-                mBoundsAnimating = true;
-            }
-            mAnimationType = animationType;
-
-            // If we are changing UI mode, as in the PiP to fullscreen
-            // transition, then we need to wait for the window to draw.
-            if (schedulePipModeChangedCallback) {
-                forAllWindows((w) -> { w.mWinAnimator.resetDrawState(); },
-                        false /* traverseTopToBottom */);
-            }
-        }
-
-        if (inPinnedWindowingMode()) {
-            try {
-                mWmService.mActivityTaskManager.notifyPinnedStackAnimationStarted();
-            } catch (RemoteException e) {
-                // I don't believe you...
-            }
-
-            if ((schedulePipModeChangedCallback || animationType == FADE_IN)
-                    && mActivityStack != null) {
-                // We need to schedule the PiP mode change before the animation up. It is possible
-                // in this case for the animation down to not have been completed, so always
-                // force-schedule and update to the client to ensure that it is notified that it
-                // is no longer in picture-in-picture mode
-                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(null,
-                        forceUpdate);
-            }
-        }
-        return true;
-    }
-
-    @Override  // AnimatesBounds
-    public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
-            boolean moveToFullscreen) {
-        if (inPinnedWindowingMode()) {
-            // Update to the final bounds if requested. This is done here instead of in the bounds
-            // animator to allow us to coordinate this after we notify the PiP mode changed
-
-            if (schedulePipModeChangedCallback) {
-                // We need to schedule the PiP mode change after the animation down, so use the
-                // final bounds
-                mActivityStack.updatePictureInPictureModeForPinnedStackAnimation(
-                        mBoundsAnimationTarget, false /* forceUpdate */);
-            }
-
-            if (mAnimationType == BoundsAnimationController.FADE_IN) {
-                setPinnedStackAlpha(1f);
-                mActivityStack.mService.notifyPinnedStackAnimationEnded();
-                return;
-            }
-
-            if (finalStackSize != null && !mCancelCurrentBoundsAnimation) {
-                setPinnedStackSize(finalStackSize, null);
-            } else {
-                // We have been canceled, so the final stack size is null, still run the
-                // animation-end logic
-                onPipAnimationEndResize();
-            }
-
-            mActivityStack.mService.notifyPinnedStackAnimationEnded();
-            if (moveToFullscreen) {
-                mActivityStack.dismissPip();
-            }
-        } else {
-            // No PiP animation, just run the normal animation-end logic
-            onPipAnimationEndResize();
-        }
-    }
-
-    /**
-     * Animates the pinned stack.
-     */
-    void animateResizePinnedStack(Rect toBounds, Rect sourceHintBounds,
-            int animationDuration, boolean fromFullscreen) {
-        if (!inPinnedWindowingMode()) {
-            return;
-        }
-        // Get the from-bounds
-        final Rect fromBounds = new Rect();
-        getBounds(fromBounds);
-
-        // Get non-null fullscreen to-bounds for animating if the bounds are null
-        @SchedulePipModeChangedState int schedulePipModeChangedState =
-                NO_PIP_MODE_CHANGED_CALLBACKS;
-        final boolean toFullscreen = toBounds == null;
-        if (toFullscreen) {
-            if (fromFullscreen) {
-                throw new IllegalArgumentException("Should not defer scheduling PiP mode"
-                        + " change on animation to fullscreen.");
-            }
-            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_START;
-
-            mWmService.getStackBounds(
-                    WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mTmpToBounds);
-            if (!mTmpToBounds.isEmpty()) {
-                // If there is a fullscreen bounds, use that
-                toBounds = new Rect(mTmpToBounds);
-            } else {
-                // Otherwise, use the display bounds
-                toBounds = new Rect();
-                getDisplayContent().getBounds(toBounds);
-            }
-        } else if (fromFullscreen) {
-            schedulePipModeChangedState = SCHEDULE_PIP_MODE_CHANGED_ON_END;
-        }
-
-        setAnimationFinalBounds(sourceHintBounds, toBounds, toFullscreen);
-
-        final Rect finalToBounds = toBounds;
-        final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
-                schedulePipModeChangedState;
-        final DisplayContent displayContent = getDisplayContent();
-        @BoundsAnimationController.AnimationType int intendedAnimationType =
-                displayContent.mBoundsAnimationController.getAnimationType();
-        if (intendedAnimationType == FADE_IN) {
-            if (fromFullscreen) {
-                setPinnedStackAlpha(0f);
-            }
-            if (toBounds.width() == fromBounds.width()
-                    && toBounds.height() == fromBounds.height()) {
-                intendedAnimationType = BoundsAnimationController.BOUNDS;
-            } else if (!fromFullscreen && !toBounds.equals(fromBounds)) {
-                // intendedAnimationType may have been reset at the end of RecentsAnimation,
-                // force it to BOUNDS type if we know for certain we're animating to
-                // a different bounds, especially for expand and collapse of PiP window.
-                intendedAnimationType = BoundsAnimationController.BOUNDS;
-            }
-        }
-
-        final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
-        mCancelCurrentBoundsAnimation = false;
-        displayContent.mBoundsAnimationController.getHandler().post(() -> {
-            displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
-                    finalToBounds, animationDuration, finalSchedulePipModeChangedState,
-                    fromFullscreen, toFullscreen, animationType);
-        });
-    }
-
-    /**
-     * Sets the current picture-in-picture aspect ratio.
-     */
-    void setPictureInPictureAspectRatio(float aspectRatio) {
-        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
-            return;
-        }
-
-        final DisplayContent displayContent = getDisplayContent();
-        if (displayContent == null) {
-            return;
-        }
-
-        if (!inPinnedWindowingMode()) {
-            return;
-        }
-
-        final PinnedStackController pinnedStackController =
-                getDisplayContent().getPinnedStackController();
-
-        if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) == 0) {
-            return;
-        }
-
-        // Notify the pinned stack controller about aspect ratio change.
-        // This would result a callback delivered from SystemUI to WM to start animation,
-        // if the bounds are ought to be altered due to aspect ratio change.
-        pinnedStackController.setAspectRatio(
-                pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
-                        ? aspectRatio : -1f);
-    }
-
-    /**
-     * Sets the current picture-in-picture actions.
-     */
-    void setPictureInPictureActions(List<RemoteAction> actions) {
-        if (!mWmService.mAtmService.mSupportsPictureInPicture) {
-            return;
-        }
-
-        if (!inPinnedWindowingMode()) {
-            return;
-        }
-
-        getDisplayContent().getPinnedStackController().setActions(actions);
-    }
-
-    @Override
-    public boolean isAttached() {
-        synchronized (mWmService.mGlobalLock) {
-            return mDisplayContent != null;
-        }
-    }
-
-    /**
-     * Called immediately prior to resizing the tasks at the end of the pinned stack animation.
-     */
-    public void onPipAnimationEndResize() {
-        synchronized (mWmService.mGlobalLock) {
-            mBoundsAnimating = false;
-            for (int i = 0; i < mChildren.size(); i++) {
-                final Task t = mChildren.get(i);
-                t.clearPreserveNonFloatingState();
-            }
-            mWmService.requestTraversal();
-        }
-    }
-
-    @Override
-    public boolean shouldDeferStartOnMoveToFullscreen() {
-        synchronized (mWmService.mGlobalLock) {
-            if (!isAttached()) {
-                // Unnecessary to pause the animation because the stack is detached.
-                return false;
-            }
-
-            // Workaround for the recents animation -- normally we need to wait for the new activity
-            // to show before starting the PiP animation, but because we start and show the home
-            // activity early for the recents animation prior to the PiP animation starting, there
-            // is no subsequent all-drawn signal. In this case, we can skip the pause when the home
-            // stack is already visible and drawn.
-            final TaskStack homeStack = mDisplayContent.getHomeStack();
-            if (homeStack == null) {
-                return true;
-            }
-            final Task homeTask = homeStack.getTopChild();
-            if (homeTask == null) {
-                return true;
-            }
-            final ActivityRecord homeApp = homeTask.getTopVisibleActivity();
-            if (!homeTask.isVisible() || homeApp == null) {
-                return true;
-            }
-            return !homeApp.allDrawn;
-        }
-    }
-
-    /**
-     * @return True if we are currently animating the pinned stack from fullscreen to non-fullscreen
-     *         bounds and we have a deferred PiP mode changed callback set with the animation.
-     */
-    public boolean deferScheduleMultiWindowModeChanged() {
-        if (inPinnedWindowingMode()) {
-            return (mBoundsAnimatingRequested || mBoundsAnimating);
-        }
-        return false;
-    }
-
-    public boolean isForceScaled() {
-        return mBoundsAnimating;
-    }
-
-    public boolean isAnimatingBounds() {
-        return mBoundsAnimating;
-    }
-
-    public boolean lastAnimatingBoundsWasToFullscreen() {
-        return mBoundsAnimatingToFullscreen;
-    }
-
-    public boolean isAnimatingBoundsToFullscreen() {
-        return isAnimatingBounds() && lastAnimatingBoundsWasToFullscreen();
-    }
-
-    public boolean pinnedStackResizeDisallowed() {
-        if (mBoundsAnimating && mCancelCurrentBoundsAnimation) {
-            return true;
-        }
-        return false;
-    }
-
-    /** Returns true if a removal action is still being deferred. */
-    boolean checkCompleteDeferredRemoval() {
-        if (isAnimating(TRANSITION | CHILDREN)) {
-            return true;
-        }
-        if (mDeferRemoval) {
-            removeImmediately();
-        }
-
-        return super.checkCompleteDeferredRemoval();
-    }
-
-    @Override
-    int getOrientation() {
-        return (canSpecifyOrientation()) ? super.getOrientation() : SCREEN_ORIENTATION_UNSET;
-    }
-
-    private boolean canSpecifyOrientation() {
-        final int windowingMode = getWindowingMode();
-        final int activityType = getActivityType();
-        return windowingMode == WINDOWING_MODE_FULLSCREEN
-                || activityType == ACTIVITY_TYPE_HOME
-                || activityType == ACTIVITY_TYPE_RECENTS
-                || activityType == ACTIVITY_TYPE_ASSISTANT;
-    }
-
-    @Override
-    Dimmer getDimmer() {
-        return mDimmer;
-    }
-
-    @Override
-    void prepareSurfaces() {
-        mDimmer.resetDimStates();
-        super.prepareSurfaces();
-        getDimBounds(mTmpDimBoundsRect);
-
-        // Bounds need to be relative, as the dim layer is a child.
-        mTmpDimBoundsRect.offsetTo(0, 0);
-        if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
-            scheduleAnimation();
-        }
-    }
-
-    @Override
-    public boolean setPinnedStackAlpha(float alpha) {
-        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
-        synchronized (mWmService.mGlobalLock) {
-            final SurfaceControl sc = getSurfaceControl();
-            if (sc == null || !sc.isValid()) {
-                // If the stack is already removed, don't bother updating any stack animation
-                return false;
-            }
-            getPendingTransaction().setAlpha(sc, mCancelCurrentBoundsAnimation ? 1 : alpha);
-            scheduleAnimation();
-            return !mCancelCurrentBoundsAnimation;
-        }
-    }
-
-    public DisplayInfo getDisplayInfo() {
-        return mDisplayContent.getDisplayInfo();
-    }
-
-    void dim(float alpha) {
-        mDimmer.dimAbove(getPendingTransaction(), alpha);
-        scheduleAnimation();
-    }
-
-    void stopDimming() {
-        mDimmer.stopDim(getPendingTransaction());
-        scheduleAnimation();
-    }
-
-    AnimatingActivityRegistry getAnimatingActivityRegistry() {
-        return mAnimatingActivityRegistry;
-    }
-
-    @Override
-    void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets,
-            Rect outSurfaceInsets) {
-        final Task task = getTopChild();
-        if (task != null) {
-            task.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
-        } else {
-            super.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets);
-        }
-    }
-
-    @Override
-    RemoteAnimationTarget createRemoteAnimationTarget(
-            RemoteAnimationController.RemoteAnimationRecord record) {
-        final Task task = getTopChild();
-        return task != null ? task.createRemoteAnimationTarget(record) : null;
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 11658f9..3e78d5e 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -92,16 +92,16 @@
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowContainer" : TAG_WM;
 
-    /** Animation layer that happens above all animating {@link TaskStack}s. */
+    /** Animation layer that happens above all animating {@link ActivityStack}s. */
     static final int ANIMATION_LAYER_STANDARD = 0;
 
-    /** Animation layer that happens above all {@link TaskStack}s. */
+    /** Animation layer that happens above all {@link ActivityStack}s. */
     static final int ANIMATION_LAYER_BOOSTED = 1;
 
     /**
      * Animation layer that is reserved for {@link WindowConfiguration#ACTIVITY_TYPE_HOME}
      * activities and all activities that are being controlled by the recents animation. This
-     * layer is generally below all {@link TaskStack}s.
+     * layer is generally below all {@link ActivityStack}s.
      */
     static final int ANIMATION_LAYER_HOME = 2;
 
@@ -124,7 +124,7 @@
 
     // Set to true when we are performing a reparenting operation so we only send one
     // onParentChanged() notification.
-    private boolean mReparenting;
+    boolean mReparenting;
 
     // List of children for this window container. List is in z-order as the children appear on
     // screen with the top-most window container at the tail of the list.
@@ -287,14 +287,12 @@
         final DisplayContent dc = newParent.getDisplayContent();
 
         mReparenting = true;
-        oldParent.removeChild(this);
+        // Oddly enough we add to the new parent before removing from the old parent to avoid
+        // issues...
         newParent.addChild(this, position);
+        oldParent.removeChild(this);
         mReparenting = false;
 
-        // Send onParentChanged notification here is we disabled sending it in setParent for
-        // reparenting case.
-        onParentChanged(newParent, oldParent);
-
         // Relayout display(s)
         dc.setLayoutNeeded();
         if (prevDc != dc) {
@@ -302,6 +300,10 @@
             prevDc.setLayoutNeeded();
         }
         getDisplayContent().layoutAndAssignWindowLayersIfNeeded();
+
+        // Send onParentChanged notification here is we disabled sending it in setParent for
+        // reparenting case.
+        onParentChanged(newParent, oldParent);
     }
 
     final protected void setParent(WindowContainer<WindowContainer> parent) {
@@ -364,7 +366,7 @@
      */
     @CallSuper
     protected void addChild(E child, Comparator<E> comparator) {
-        if (child.getParent() != null) {
+        if (!child.mReparenting && child.getParent() != null) {
             throw new IllegalArgumentException("addChild: container=" + child.getName()
                     + " is already a child of container=" + child.getParent().getName()
                     + " can't add to container=" + getName());
@@ -395,7 +397,7 @@
     /** Adds the input window container has a child of this container at the input index. */
     @CallSuper
     void addChild(E child, int index) {
-        if (child.getParent() != null) {
+        if (!child.mReparenting && child.getParent() != null) {
             throw new IllegalArgumentException("addChild: container=" + child.getName()
                     + " is already a child of container=" + child.getParent().getName()
                     + " can't add to container=" + getName()
@@ -440,7 +442,9 @@
     void removeChild(E child) {
         if (mChildren.remove(child)) {
             onChildRemoved(child);
-            child.setParent(null);
+            if (!child.mReparenting) {
+                child.setParent(null);
+            }
         } else {
             throw new IllegalArgumentException("removeChild: container=" + child.getName()
                     + " is not a child of container=" + getName());
@@ -486,6 +490,7 @@
             }
 
             mSurfaceControl = null;
+            mLastSurfacePosition.set(0, 0);
             scheduleAnimation();
         }
 
@@ -566,15 +571,9 @@
                     + " current parent=" + child.getParent());
         }
 
-        if ((position < 0 && position != POSITION_BOTTOM)
-                || (position > mChildren.size() && position != POSITION_TOP)) {
-            throw new IllegalArgumentException("positionAt: invalid position=" + position
-                    + ", children number=" + mChildren.size());
-        }
-
         if (position >= mChildren.size() - 1) {
             position = POSITION_TOP;
-        } else if (position == 0) {
+        } else if (position <= 0) {
             position = POSITION_BOTTOM;
         }
 
@@ -1056,9 +1055,9 @@
     }
 
     // TODO: Users would have their own window containers under the display container?
-    void switchUser() {
+    void switchUser(int userId) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
-            mChildren.get(i).switchUser();
+            mChildren.get(i).switchUser(userId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowFrames.java b/services/core/java/com/android/server/wm/WindowFrames.java
index 9fe4760..84fcfbd 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;
@@ -61,7 +57,7 @@
     public final Rect mParentFrame = new Rect();
 
     /**
-     * The entire screen area of the {@link TaskStack} this window is in. Usually equal to the
+     * The entire screen area of the {@link ActivityStack} this window is in. Usually equal to the
      * screen area of the device.
      *
      * TODO(b/111611553): The name is unclear and most likely should be swapped with
@@ -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 56d36e0..519cc21 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));
@@ -1924,7 +1934,7 @@
                 // re-factor.
                 activity.firstWindowDrawn = false;
                 activity.clearAllDrawn();
-                final TaskStack stack = activity.getStack();
+                final ActivityStack stack = activity.getStack();
                 if (stack != null) {
                     stack.mExitingActivities.remove(activity);
                 }
@@ -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));
@@ -2753,7 +2763,7 @@
     @Override
     public void getStackBounds(int windowingMode, int activityType, Rect bounds) {
         synchronized (mGlobalLock) {
-            final TaskStack stack = mRoot.getStack(windowingMode, activityType);
+            final ActivityStack stack = mRoot.getStack(windowingMode, activityType);
             if (stack != null) {
                 stack.getBounds(bounds);
                 return;
@@ -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
@@ -3200,12 +3212,12 @@
             mKeyguardDisableHandler.setCurrentUser(newUserId);
 
             // Hide windows that should not be seen by the new user.
-            mRoot.switchUser();
+            mRoot.switchUser(newUserId);
             mWindowPlacerLocked.performSurfacePlacement();
 
             // Notify whether the docked stack exists for the current user
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final TaskStack stack =
+            final ActivityStack stack =
                     displayContent.getSplitScreenPrimaryStackIgnoringVisibility();
             displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
                     stack != null && stack.hasTaskForUser(newUserId));
@@ -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) {
@@ -4359,7 +4368,7 @@
         return mRoot.getTopFocusedDisplayContent().mCurrentFocus;
     }
 
-    TaskStack getImeFocusStackLocked() {
+    ActivityStack getImeFocusStackLocked() {
         // Don't use mCurrentFocus.getStack() because it returns home stack for system windows.
         // Also don't use mInputMethodTarget's stack, because some window with FLAG_NOT_FOCUSABLE
         // and FLAG_ALT_FOCUSABLE_IM flags both set might be set to IME target so they're moved
@@ -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();
         }
     }
 
@@ -6417,7 +6388,7 @@
     @Override
     public int getDockedStackSide() {
         synchronized (mGlobalLock) {
-            final TaskStack dockedStack = getDefaultDisplayContentLocked()
+            final ActivityStack dockedStack = getDefaultDisplayContentLocked()
                     .getSplitScreenPrimaryStackIgnoringVisibility();
             return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
         }
@@ -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();
         }
     }
 
@@ -7669,7 +7642,7 @@
             return;
         }
 
-        final TaskStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getTaskStack();
         // We ignore home stack since we don't want home stack to move to front when touched.
         // Specifically, in freeform we don't want tapping on home to cause the freeform apps to go
         // behind home. See b/117376413
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 eb75684..d63fbc21 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -165,7 +165,7 @@
     // all activities running in the process
     private final ArrayList<ActivityRecord> mActivities = new ArrayList<>();
     // any tasks this process had run root activities in
-    private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<>();
+    private final ArrayList<Task> mRecentTasks = new ArrayList<>();
     // The most recent top-most activity that was resumed in the process for pre-Q app.
     private ActivityRecord mPreQTopResumedActivity = null;
     // The last time an activity was launched in the process
@@ -550,7 +550,7 @@
 
     private boolean hasActivityInVisibleTask() {
         for (int i = mActivities.size() - 1; i >= 0; --i) {
-            TaskRecord task = mActivities.get(i).getTaskRecord();
+            Task task = mActivities.get(i).getTask();
             if (task == null) {
                 continue;
             }
@@ -601,8 +601,8 @@
 
         // Compare the z-order of ActivityStacks if both activities landed on same display.
         if (display == topDisplay
-                && mPreQTopResumedActivity.getActivityStack().mTaskStack.compareTo(
-                activity.getActivityStack().mTaskStack) <= 0) {
+                && mPreQTopResumedActivity.getActivityStack().compareTo(
+                        activity.getActivityStack()) <= 0) {
             canUpdate = true;
         }
 
@@ -702,18 +702,18 @@
         }
         ActivityRecord hist = mActivities.get(0);
         intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_APP, hist.packageName);
-        intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTaskRecord().mTaskId);
+        intent.putExtra(HeavyWeightSwitcherActivity.KEY_CUR_TASK, hist.getTask().mTaskId);
     }
 
-    boolean shouldKillProcessForRemovedTask(TaskRecord tr) {
+    boolean shouldKillProcessForRemovedTask(Task task) {
         for (int k = 0; k < mActivities.size(); k++) {
             final ActivityRecord activity = mActivities.get(k);
             if (!activity.stopped) {
                 // Don't kill process(es) that has an activity not stopped.
                 return false;
             }
-            final TaskRecord otherTask = activity.getTaskRecord();
-            if (tr.mTaskId != otherTask.mTaskId && otherTask.inRecents) {
+            final Task otherTask = activity.getTask();
+            if (task.mTaskId != otherTask.mTaskId && otherTask.inRecents) {
                 // Don't kill process(es) that has an activity in a different task that is
                 // also in recents.
                 return false;
@@ -722,11 +722,11 @@
         return true;
     }
 
-    ArraySet<TaskRecord> getReleaseSomeActivitiesTasks() {
+    ArraySet<Task> getReleaseSomeActivitiesTasks() {
         // Examine all activities currently running in the process.
-        TaskRecord firstTask = null;
+        Task firstTask = null;
         // Tasks is non-null only if two or more tasks are found.
-        ArraySet<TaskRecord> tasks = null;
+        ArraySet<Task> tasks = null;
         if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Trying to release some activities in " + this);
         for (int i = 0; i < mActivities.size(); i++) {
             final ActivityRecord r = mActivities.get(i);
@@ -745,7 +745,7 @@
                 continue;
             }
 
-            final TaskRecord task = r.getTaskRecord();
+            final Task task = r.getTask();
             if (task != null) {
                 if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Collecting release task " + task
                         + " from " + r);
@@ -794,7 +794,7 @@
                     }
                 }
                 if (r.visible) {
-                    final TaskRecord task = r.getTaskRecord();
+                    final Task task = r.getTask();
                     if (task != null && minTaskLayer > 0) {
                         final int layer = task.mLayerRank;
                         if (layer >= 0 && minTaskLayer > layer) {
@@ -1023,11 +1023,11 @@
         return (mListener != null) ? mListener.getCpuTime() : 0;
     }
 
-    void addRecentTask(TaskRecord task) {
+    void addRecentTask(Task task) {
         mRecentTasks.add(task);
     }
 
-    void removeRecentTask(TaskRecord task) {
+    void removeRecentTask(Task task) {
         mRecentTasks.remove(task);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d196c34..f98e307 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -35,7 +35,6 @@
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
@@ -1007,7 +1006,7 @@
                 }
             }
 
-            final TaskStack stack = getStack();
+            final ActivityStack stack = getStack();
             if (inPinnedWindowingMode() && stack != null
                     && stack.lastAnimatingBoundsWasToFullscreen()) {
                 // PIP edge case: When going from pinned to fullscreen, we apply a
@@ -1048,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()) {
@@ -1095,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);
@@ -1171,11 +1160,6 @@
     }
 
     @Override
-    public Rect getOverscanFrameLw() {
-        return mWindowFrames.mOverscanFrame;
-    }
-
-    @Override
     public Rect getContentFrameLw() {
         return mWindowFrames.mContentFrame;
     }
@@ -1420,7 +1404,7 @@
         return mActivityRecord != null ? mActivityRecord.getTask() : null;
     }
 
-    TaskStack getStack() {
+    ActivityStack getStack() {
         Task task = getTask();
         if (task != null) {
             if (task.getTaskStack() != null) {
@@ -1443,7 +1427,7 @@
         bounds.setEmpty();
         mTmpRect.setEmpty();
         if (intersectWithStackBounds) {
-            final TaskStack stack = task.getTaskStack();
+            final ActivityStack stack = task.getTaskStack();
             if (stack != null) {
                 stack.getDimBounds(mTmpRect);
             } else {
@@ -2151,20 +2135,19 @@
             return false;
         }
 
-        final TaskStack stack = getStack();
+        final ActivityStack stack = getStack();
         if (stack != null && stack.shouldIgnoreInput()) {
             // Ignore when the stack shouldn't receive input event.
             // (i.e. the minimized stack in split screen mode.)
             return false;
         }
 
-        final int fl = mAttrs.flags & (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
-        final int type = mAttrs.type;
-
-        // Can only be an IME target if both FLAG_NOT_FOCUSABLE and FLAG_ALT_FOCUSABLE_IM are set or
-        // both are cleared...and not a starting window.
-        if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM)
-                && type != TYPE_APPLICATION_STARTING) {
+        // Can be an IME target only if:
+        // 1. FLAG_NOT_FOCUSABLE is not set
+        // 2. FLAG_ALT_FOCUSABLE_IM is not set
+        // 3. not a starting window.
+        if (!WindowManager.LayoutParams.mayUseInputMethod(mAttrs.flags)
+                || mAttrs.type == TYPE_APPLICATION_STARTING) {
             return false;
         }
 
@@ -2307,8 +2290,8 @@
     }
 
     @Override
-    void switchUser() {
-        super.switchUser();
+    void switchUser(int userId) {
+        super.switchUser(userId);
         if (isHiddenFromUserLocked()) {
             if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + this
                     + ", attrs=" + mAttrs.type + ", belonging to " + mOwnerUid);
@@ -2556,7 +2539,7 @@
                             // just in case they have the divider at an unstable position. Better
                             // also reset drag resizing state, because the owner can't do it
                             // anymore.
-                            final TaskStack stack =
+                            final ActivityStack stack =
                                     dc.getSplitScreenPrimaryStackIgnoringVisibility();
                             if (stack != null) {
                                 stack.resetDockedStackToMiddle();
@@ -3153,7 +3136,7 @@
             return;
         }
 
-        final TaskStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getTaskStack();
         if (stack == null) {
             return;
         }
@@ -3167,7 +3150,7 @@
             return;
         }
 
-        final TaskStack stack = task.getTaskStack();
+        final ActivityStack stack = task.getTaskStack();
         if (stack == null) {
             return;
         }
@@ -3267,11 +3250,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();
@@ -3283,8 +3264,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.
@@ -3292,8 +3273,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) {
@@ -3356,7 +3337,7 @@
             mClient.insetsChanged(
                     getDisplayContent().getInsetsPolicy().getInsetsForDispatch(this));
         } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to deliver inset state change", e);
+            Slog.w(TAG, "Failed to deliver inset state change w=" + this, e);
         }
     }
 
@@ -3418,21 +3399,21 @@
     }
 
     private int getStackId() {
-        final TaskStack stack = getStack();
+        final ActivityStack stack = getStack();
         if (stack == null) {
             return INVALID_STACK_ID;
         }
         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));
@@ -3649,7 +3630,7 @@
 
     @Override
     void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        final TaskStack stack = getStack();
+        final ActivityStack stack = getStack();
         pw.print(prefix + "mDisplayId=" + getDisplayId());
         if (stack != null) {
             pw.print(" stackId=" + stack.mStackId);
@@ -5099,7 +5080,7 @@
             outPoint.offset(-parentBounds.left, -parentBounds.top);
         }
 
-        TaskStack stack = getStack();
+        ActivityStack stack = getStack();
 
         // If we have stack outsets, that means the top-left
         // will be outset, and we need to inset ourselves
@@ -5284,13 +5265,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/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a853828..94aff7b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1016,7 +1016,7 @@
                         mSurfaceController.deferTransactionUntil(mSurfaceController.mSurfaceControl,
                                 mWin.getFrameNumber());
                     } else {
-                        final TaskStack stack = mWin.getStack();
+                        final ActivityStack stack = mWin.getStack();
                         mTmpPos.x = 0;
                         mTmpPos.y = 0;
                         if (stack != null) {
diff --git a/services/devicepolicy/Android.bp b/services/devicepolicy/Android.bp
index 91c05a8..bffa44e 100644
--- a/services/devicepolicy/Android.bp
+++ b/services/devicepolicy/Android.bp
@@ -4,6 +4,7 @@
 
     libs: [
         "services.core",
+        "app-compat-annotations",
     ],
 
     plugins: [
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/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 71f7d2c..f2e118d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -56,6 +56,7 @@
 import com.android.server.DeviceIdleInternal;
 import com.android.server.LocalServices;
 import com.android.server.job.controllers.JobStatus;
+import com.android.server.usage.AppStandbyInternal;
 
 import org.junit.After;
 import org.junit.Before;
@@ -100,6 +101,8 @@
         when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
         doReturn(mActivityMangerInternal)
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
+        doReturn(mock(AppStandbyInternal.class))
+                .when(() -> LocalServices.getService(AppStandbyInternal.class));
         doReturn(mock(UsageStatsManagerInternal.class))
                 .when(() -> LocalServices.getService(UsageStatsManagerInternal.class));
         // Called in BackgroundJobsController constructor.
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 5bd08c0..bc0b184 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -78,6 +78,7 @@
 import com.android.server.job.JobStore;
 import com.android.server.job.controllers.QuotaController.ExecutionStats;
 import com.android.server.job.controllers.QuotaController.TimingSession;
+import com.android.server.usage.AppStandbyInternal;
 
 import org.junit.After;
 import org.junit.Before;
@@ -150,6 +151,8 @@
         when(mContext.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
         doReturn(mActivityMangerInternal)
                 .when(() -> LocalServices.getService(ActivityManagerInternal.class));
+        doReturn(mock(AppStandbyInternal.class))
+                .when(() -> LocalServices.getService(AppStandbyInternal.class));
         doReturn(mock(BatteryManagerInternal.class))
                 .when(() -> LocalServices.getService(BatteryManagerInternal.class));
         doReturn(mUsageStatsManager)
diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
index 0605d9e..50437b4 100644
--- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java
@@ -36,7 +36,7 @@
     public void test1() {
         assertTrue("dynamic_system service available", mService != null);
         try {
-            mService.startInstallation("userdata", 8L << 30, false);
+            mService.startInstallation();
             fail("DynamicSystemService did not throw SecurityException as expected");
         } catch (SecurityException e) {
             // expected
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
index 597d337..99dd9a1 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityServiceConnectionTest.java
@@ -44,6 +44,7 @@
 import android.testing.DexmakerShareClassLoaderRule;
 import android.view.Display;
 
+import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
 import org.junit.After;
@@ -80,6 +81,7 @@
     @Mock ResolveInfo mMockResolveInfo;
     @Mock AccessibilitySecurityPolicy mMockSecurityPolicy;
     @Mock AccessibilityWindowManager mMockA11yWindowManager;
+    @Mock ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
     @Mock WindowManagerInternal mMockWindowManagerInternal;
     @Mock SystemActionPerformer mMockSystemActionPerformer;
@@ -111,7 +113,8 @@
         mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
                 COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
                 mMockSecurityPolicy, mMockSystemSupport, mMockWindowManagerInternal,
-                mMockSystemActionPerformer, mMockA11yWindowManager);
+                mMockSystemActionPerformer, mMockA11yWindowManager,
+                mMockActivityTaskManagerInternal);
         when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
new file mode 100644
index 0000000..2e2270b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/content/SyncStorageEngineTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.content;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+import android.content.Context;
+import android.content.SyncStatusInfo;
+import android.util.Pair;
+import android.util.SparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * Tests for {@link SyncStorageEngine}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class SyncStorageEngineTest {
+
+    private Context mContext;
+    private SyncStorageEngine mSyncStorageEngine;
+
+    private static final int NUM_SYNC_STATUS = 100;
+    private static final int NUM_PERIODIC_SYNC_TIMES = 20;
+    private static final int NUM_EVENTS = 10;
+    private static final int NUM_SOURCES = 6;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getTargetContext();
+        mSyncStorageEngine = SyncStorageEngine.newTestInstance(mContext);
+    }
+
+    @Test
+    public void testStatisticsReadWrite() {
+        populateDayStats(mSyncStorageEngine.mDayStats);
+        mSyncStorageEngine.writeStatisticsLocked();
+
+        final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
+        verifyDayStats(mSyncStorageEngine.mDayStats, other.getDayStatistics());
+    }
+
+    @Test
+    public void testStatusReadWrite() {
+        populateStatus(mSyncStorageEngine.mSyncStatus);
+        mSyncStorageEngine.writeStatusLocked();
+
+        final SyncStorageEngine other = SyncStorageEngine.newTestInstance(mContext);
+        for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+            other.mAuthorities.put(i, null);
+        }
+        other.readStatusLocked();
+        verifyStatus(mSyncStorageEngine.mSyncStatus, other.mSyncStatus);
+    }
+
+    private void populateDayStats(SyncStorageEngine.DayStats[] dayStats) {
+        final Random r = new Random(1);
+        for (int i = 0; i < dayStats.length; i++) {
+            final SyncStorageEngine.DayStats ds = new SyncStorageEngine.DayStats(i);
+            ds.successCount = r.nextInt();
+            ds.successTime = r.nextLong();
+            ds.failureCount = r.nextInt();
+            ds.failureTime = r.nextLong();
+            dayStats[i] = ds;
+        }
+    }
+
+    private void verifyDayStats(SyncStorageEngine.DayStats[] dayStats,
+            SyncStorageEngine.DayStats[] dayStatsOther) {
+        assertEquals(dayStatsOther.length, dayStats.length);
+        for (int i = 0; i < dayStatsOther.length; i++) {
+            final SyncStorageEngine.DayStats ds = dayStats[i];
+            final SyncStorageEngine.DayStats dsOther = dayStatsOther[i];
+            assertEquals(dsOther.day, ds.day);
+            assertEquals(dsOther.successCount, ds.successCount);
+            assertEquals(dsOther.successTime, ds.successTime);
+            assertEquals(dsOther.failureCount, ds.failureCount);
+            assertEquals(dsOther.failureTime, ds.failureTime);
+        }
+    }
+
+    private void populateStatus(SparseArray<SyncStatusInfo> syncStatus) {
+        final Random r = new Random(1);
+        for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+            final SyncStatusInfo ss = new SyncStatusInfo(i);
+            ss.lastSuccessTime = r.nextLong();
+            ss.lastSuccessSource = r.nextInt();
+            ss.lastFailureTime = r.nextLong();
+            ss.lastFailureSource = r.nextInt();
+            ss.lastFailureMesg = "fail_msg_" + r.nextInt();
+            ss.initialFailureTime = r.nextLong();
+            ss.initialize = r.nextBoolean();
+            for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
+                ss.addPeriodicSyncTime(r.nextLong());
+            }
+            final ArrayList<Pair<Long, String>> lastEventInfos = new ArrayList<>();
+            for (int j = 0; j < NUM_EVENTS; j++) {
+                lastEventInfos.add(new Pair<>(r.nextLong(), "event_" + r.nextInt()));
+            }
+            ss.populateLastEventsInformation(lastEventInfos);
+            ss.lastTodayResetTime = r.nextLong();
+            populateStats(ss.totalStats, r);
+            populateStats(ss.todayStats, r);
+            populateStats(ss.yesterdayStats, r);
+            for (int j = 0; j < NUM_SOURCES; j++) {
+                ss.perSourceLastSuccessTimes[j] = r.nextLong();
+            }
+            for (int j = 0; j < NUM_SOURCES; j++) {
+                ss.perSourceLastFailureTimes[j] = r.nextLong();
+            }
+            syncStatus.put(i, ss);
+        }
+    }
+
+    private void populateStats(SyncStatusInfo.Stats stats, Random r) {
+        stats.totalElapsedTime = r.nextLong();
+        stats.numSyncs = r.nextInt();
+        stats.numFailures = r.nextInt();
+        stats.numCancels = r.nextInt();
+        stats.numSourceOther = r.nextInt();
+        stats.numSourceLocal = r.nextInt();
+        stats.numSourcePoll = r.nextInt();
+        stats.numSourceUser = r.nextInt();
+        stats.numSourcePeriodic = r.nextInt();
+        stats.numSourceFeed = r.nextInt();
+    }
+
+    private void verifyStatus(SparseArray<SyncStatusInfo> syncStatus,
+            SparseArray<SyncStatusInfo> syncStatusOther) {
+        assertEquals(syncStatusOther.size(), syncStatus.size());
+        for (int i = 0; i < NUM_SYNC_STATUS; i++) {
+            final SyncStatusInfo ss = syncStatus.valueAt(i);
+            final SyncStatusInfo ssOther = syncStatusOther.valueAt(i);
+            assertEquals(ssOther.authorityId, ss.authorityId);
+            assertEquals(ssOther.lastSuccessTime, ss.lastSuccessTime);
+            assertEquals(ssOther.lastSuccessSource, ss.lastSuccessSource);
+            assertEquals(ssOther.lastFailureTime, ss.lastFailureTime);
+            assertEquals(ssOther.lastFailureSource, ss.lastFailureSource);
+            assertEquals(ssOther.lastFailureMesg, ss.lastFailureMesg);
+            assertFalse(ssOther.pending); // pending is always set to false when read
+            assertEquals(ssOther.initialize, ss.initialize);
+            assertEquals(ssOther.getPeriodicSyncTimesSize(), NUM_PERIODIC_SYNC_TIMES);
+            for (int j = 0; j < NUM_PERIODIC_SYNC_TIMES; j++) {
+                assertEquals(ssOther.getPeriodicSyncTime(j), ss.getPeriodicSyncTime(j));
+            }
+            assertEquals(ssOther.getEventCount(), NUM_EVENTS);
+            for (int j = 0; j < NUM_EVENTS; j++) {
+                assertEquals(ssOther.getEventTime(j), ss.getEventTime(j));
+                assertEquals(ssOther.getEvent(j), ss.getEvent(j));
+            }
+            assertEquals(ssOther.lastTodayResetTime, ss.lastTodayResetTime);
+            verifyStats(ss.totalStats, ssOther.totalStats);
+            verifyStats(ss.todayStats, ssOther.todayStats);
+            verifyStats(ss.yesterdayStats, ssOther.yesterdayStats);
+            assertEquals(ssOther.perSourceLastSuccessTimes.length, NUM_SOURCES);
+            for (int j = 0; j < NUM_SOURCES; j++) {
+                assertEquals(ssOther.perSourceLastSuccessTimes[j], ss.perSourceLastSuccessTimes[j]);
+            }
+            assertEquals(ssOther.perSourceLastFailureTimes.length, NUM_SOURCES);
+            for (int j = 0; j < NUM_SOURCES; j++) {
+                assertEquals(ssOther.perSourceLastFailureTimes[j], ss.perSourceLastFailureTimes[j]);
+            }
+        }
+    }
+
+    private void verifyStats(SyncStatusInfo.Stats stats, SyncStatusInfo.Stats statsOther) {
+        assertEquals(statsOther.totalElapsedTime, stats.totalElapsedTime);
+        assertEquals(statsOther.numSyncs, stats.numSyncs);
+        assertEquals(statsOther.numFailures, stats.numFailures);
+        assertEquals(statsOther.numCancels, stats.numCancels);
+        assertEquals(statsOther.numSourceOther, stats.numSourceOther);
+        assertEquals(statsOther.numSourceLocal, stats.numSourceLocal);
+        assertEquals(statsOther.numSourcePoll, stats.numSourcePoll);
+        assertEquals(statsOther.numSourceUser, stats.numSourceUser);
+        assertEquals(statsOther.numSourcePeriodic, stats.numSourcePeriodic);
+        assertEquals(statsOther.numSourceFeed, stats.numSourceFeed);
+    }
+}
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/engine/RuleEvaluatorTest.java b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
index baf1ed0..e52aca3 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/engine/RuleEvaluatorTest.java
@@ -16,11 +16,15 @@
 
 package com.android.server.integrity.engine;
 
+import static com.android.server.integrity.model.IntegrityCheckResult.Effect.ALLOW;
+import static com.android.server.integrity.model.IntegrityCheckResult.Effect.DENY;
+
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 
 import com.android.server.integrity.model.AppInstallMetadata;
 import com.android.server.integrity.model.AtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
+import com.android.server.integrity.model.IntegrityCheckResult;
 import com.android.server.integrity.model.OpenFormula;
 import com.android.server.integrity.model.Rule;
 
@@ -43,141 +47,176 @@
             new AppInstallMetadata.Builder()
                     .setPackageName(PACKAGE_NAME_1)
                     .setAppCertificate(APP_CERTIFICATE)
+                    .setVersionCode(2)
                     .build();
 
     @Test
-    public void testMatchRules_emptyRules() {
+    public void testEvaluateRules_noRules_allow() {
         List<Rule> rules = new ArrayList<>();
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);
+        IntegrityCheckResult result = RuleEvaluator.evaluateRules(rules, APP_INSTALL_METADATA);
 
-        assertEquals(Rule.EMPTY, matchedRule);
+        assertEquals(ALLOW, result.getEffect());
     }
 
     @Test
-    public void testMatchRules_emptyMatch() {
-        Rule rule1 = new Rule(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_2), Rule.Effect.DENY);
+    public void testEvaluateRules_noMatchedRules_allow() {
+        Rule rule1 =
+                new Rule(
+                        new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+                        Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule1),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule1), APP_INSTALL_METADATA);
 
-        assertEquals(Rule.EMPTY, matchedRule);
-    }
-
-
-    @Test
-    public void testMatchRules_oneMatch() {
-        Rule rule1 = new Rule(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_1), Rule.Effect.DENY);
-        Rule rule2 = new Rule(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_2), Rule.Effect.DENY);
-
-        Rule matchedRule = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2),
-                APP_INSTALL_METADATA);
-
-        assertEquals(rule1, matchedRule);
+        assertEquals(ALLOW, result.getEffect());
     }
 
     @Test
-    public void testMatchRules_multipleMatches() {
-        Rule rule1 = new Rule(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_1), Rule.Effect.DENY);
-        OpenFormula openFormula2 = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_1),
-                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
-                        AtomicFormula.Operator.EQ,
-                        APP_CERTIFICATE)));
-        Rule rule2 = new Rule(
-                openFormula2, Rule.Effect.DENY);
+    public void testEvaluateRules_oneMatch_deny() {
+        Rule rule1 =
+                new Rule(
+                        new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                        Rule.DENY);
+        Rule rule2 =
+                new Rule(
+                        new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+                        Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
 
-        assertNotEquals(Rule.EMPTY, matchedRule);
+        assertEquals(DENY, result.getEffect());
+        assertEquals(rule1, result.getRule());
     }
 
     @Test
-    public void testMatchRules_ruleWithNot() {
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.NOT,
-                Collections.singletonList(
-                        new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                                PACKAGE_NAME_2)));
-        Rule rule = new Rule(openFormula, Rule.Effect.DENY);
+    public void testEvaluateRules_multipleMatches_deny() {
+        Rule rule1 =
+                new Rule(
+                        new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                        Rule.DENY);
+        OpenFormula openFormula2 =
+                new OpenFormula(
+                        OpenFormula.AND,
+                        Arrays.asList(
+                                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                                new StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+        Rule rule2 = new Rule(openFormula2, Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
 
-        assertEquals(rule, matchedRule);
+        assertEquals(DENY, result.getEffect());
+        assertEquals(rule1, result.getRule());
     }
 
     @Test
-    public void testMatchRules_ruleWithIntegerOperators() {
-        Rule rule1 = new Rule(
-                new AtomicFormula(AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.GT,
-                        1), Rule.Effect.DENY);
+    public void testEvaluateRules_ruleWithNot_deny() {
+        OpenFormula openFormula =
+                new OpenFormula(
+                        OpenFormula.NOT,
+                        Collections.singletonList(
+                                new StringAtomicFormula(
+                                        AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2)));
+        Rule rule = new Rule(openFormula, Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule1),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
 
-        assertEquals(rule1, matchedRule);
+        assertEquals(DENY, result.getEffect());
+        assertEquals(rule, result.getRule());
     }
 
     @Test
-    public void testMatchRules_validForm() {
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_1),
-                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
-                        AtomicFormula.Operator.EQ,
-                        APP_CERTIFICATE)));
-        Rule rule = new Rule(
-                openFormula, Rule.Effect.DENY);
+    public void testEvaluateRules_ruleWithIntegerOperators_deny() {
+        Rule rule =
+                new Rule(
+                        new AtomicFormula.IntAtomicFormula(
+                                AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1),
+                        Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
 
-        assertEquals(rule, matchedRule);
+        assertEquals(DENY, result.getEffect());
+        assertEquals(rule, result.getRule());
     }
 
     @Test
-    public void testMatchRules_ruleNotInDNF() {
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.OR, Arrays.asList(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_1),
-                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
-                        AtomicFormula.Operator.EQ,
-                        APP_CERTIFICATE)));
-        Rule rule = new Rule(
-                openFormula, Rule.Effect.DENY);
+    public void testEvaluateRules_validForm_deny() {
+        OpenFormula openFormula =
+                new OpenFormula(
+                        OpenFormula.AND,
+                        Arrays.asList(
+                                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                                new StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+        Rule rule = new Rule(openFormula, Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
 
-        assertEquals(Rule.EMPTY, matchedRule);
+        assertEquals(DENY, result.getEffect());
+        assertEquals(rule, result.getRule());
     }
 
     @Test
-    public void testMatchRules_openFormulaWithNot() {
-        OpenFormula openSubFormula = new OpenFormula(OpenFormula.Connector.AND, Arrays.asList(
-                new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        PACKAGE_NAME_2),
-                new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE,
-                        AtomicFormula.Operator.EQ,
-                        APP_CERTIFICATE)));
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.NOT,
-                Collections.singletonList(openSubFormula));
-        Rule rule = new Rule(
-                openFormula, Rule.Effect.DENY);
+    public void testEvaluateRules_ruleNotInDNF_ignoreAndAllow() {
+        OpenFormula openFormula =
+                new OpenFormula(
+                        OpenFormula.OR,
+                        Arrays.asList(
+                                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                                new StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+        Rule rule = new Rule(openFormula, Rule.DENY);
 
-        Rule matchedRule = RuleEvaluator.evaluateRules(Collections.singletonList(rule),
-                APP_INSTALL_METADATA);
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
 
-        assertEquals(Rule.EMPTY, matchedRule);
+        assertEquals(ALLOW, result.getEffect());
+    }
+
+    @Test
+    public void testEvaluateRules_openFormulaWithNot_allow() {
+        OpenFormula openSubFormula =
+                new OpenFormula(
+                        OpenFormula.AND,
+                        Arrays.asList(
+                                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_2),
+                                new StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.NOT, Collections.singletonList(openSubFormula));
+        Rule rule = new Rule(openFormula, Rule.DENY);
+
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Collections.singletonList(rule), APP_INSTALL_METADATA);
+
+        assertEquals(ALLOW, result.getEffect());
+    }
+
+    @Test
+    public void testEvaluateRules_forceAllow() {
+        Rule rule1 =
+                new Rule(
+                        new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                        Rule.FORCE_ALLOW);
+        OpenFormula openFormula2 =
+                new OpenFormula(
+                        OpenFormula.AND,
+                        Arrays.asList(
+                                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME_1),
+                                new StringAtomicFormula(
+                                        AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE)));
+        Rule rule2 = new Rule(openFormula2, Rule.DENY);
+
+        IntegrityCheckResult result =
+                RuleEvaluator.evaluateRules(Arrays.asList(rule1, rule2), APP_INSTALL_METADATA);
+
+        assertEquals(ALLOW, result.getEffect());
+        assertEquals(rule1, result.getRule());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
index 1cb2fb3..c8c5eca 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/AtomicFormulaTest.java
@@ -19,6 +19,14 @@
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import com.android.server.integrity.model.AtomicFormula.BooleanAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.IntAtomicFormula;
+import com.android.server.integrity.model.AtomicFormula.StringAtomicFormula;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -29,32 +37,26 @@
 
     @Test
     public void testValidAtomicFormula_stringValue() {
-        AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME,
-                AtomicFormula.Operator.EQ, "com.test.app");
+        StringAtomicFormula stringAtomicFormula =
+                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
 
-        assertEquals(AtomicFormula.Key.PACKAGE_NAME, atomicFormula.getKey());
-        assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
-        assertEquals("com.test.app", atomicFormula.getStringValue());
+        assertEquals(AtomicFormula.PACKAGE_NAME, stringAtomicFormula.getKey());
     }
 
     @Test
     public void testValidAtomicFormula_intValue() {
-        AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.VERSION_CODE,
-                AtomicFormula.Operator.LE, 1);
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
 
-        assertEquals(AtomicFormula.Key.VERSION_CODE, atomicFormula.getKey());
-        assertEquals(AtomicFormula.Operator.LE, atomicFormula.getOperator());
-        assertEquals(1, atomicFormula.getIntValue().intValue());
+        assertEquals(AtomicFormula.VERSION_CODE, intAtomicFormula.getKey());
     }
 
     @Test
     public void testValidAtomicFormula_boolValue() {
-        AtomicFormula atomicFormula = new AtomicFormula(AtomicFormula.Key.PRE_INSTALLED,
-                AtomicFormula.Operator.EQ, true);
+        BooleanAtomicFormula atomicFormula =
+                new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
 
-        assertEquals(AtomicFormula.Key.PRE_INSTALLED, atomicFormula.getKey());
-        assertEquals(AtomicFormula.Operator.EQ, atomicFormula.getOperator());
-        assertEquals(true, atomicFormula.getBoolValue());
+        assertEquals(AtomicFormula.PRE_INSTALLED, atomicFormula.getKey());
     }
 
     @Test
@@ -62,9 +64,9 @@
         assertExpectException(
                 IllegalArgumentException.class,
                 /* expectedExceptionMessageRegex */
-                String.format("Key %s cannot have string value", AtomicFormula.Key.VERSION_CODE),
-                () -> new AtomicFormula(AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ,
-                        "test-value"));
+                String.format(
+                        "Key VERSION_CODE cannot be used with StringAtomicFormula"),
+                () -> new StringAtomicFormula(AtomicFormula.VERSION_CODE, "test-value"));
     }
 
     @Test
@@ -72,9 +74,9 @@
         assertExpectException(
                 IllegalArgumentException.class,
                 /* expectedExceptionMessageRegex */
-                String.format("Key %s cannot have integer value", AtomicFormula.Key.PACKAGE_NAME),
-                () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        1));
+                String.format(
+                        "Key PACKAGE_NAME cannot be used with IntAtomicFormula"),
+                () -> new IntAtomicFormula(AtomicFormula.PACKAGE_NAME, AtomicFormula.EQ, 1));
     }
 
     @Test
@@ -82,19 +84,193 @@
         assertExpectException(
                 IllegalArgumentException.class,
                 /* expectedExceptionMessageRegex */
-                String.format("Key %s cannot have boolean value", AtomicFormula.Key.PACKAGE_NAME),
-                () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                        true));
+                String.format(
+                        "Key PACKAGE_NAME cannot be used with BooleanAtomicFormula"),
+                () -> new BooleanAtomicFormula(AtomicFormula.PACKAGE_NAME, true));
     }
 
     @Test
-    public void testValidateOperator_invalidKeyOperatorPair() {
-        assertExpectException(
-                IllegalArgumentException.class,
-                /* expectedExceptionMessageRegex */
-                String.format("Invalid operator %s used for key %s",
-                        AtomicFormula.Operator.LE, AtomicFormula.Key.PACKAGE_NAME),
-                () -> new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.LE,
-                        "test-value"));
+    public void testIsSatisfiable_string_true() {
+        StringAtomicFormula stringAtomicFormula =
+                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("com.test.app").build();
+
+        assertTrue(stringAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_string_false() {
+        StringAtomicFormula stringAtomicFormula =
+                new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "com.test.app");
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("com.foo.bar").build();
+
+        assertFalse(stringAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_eq_true() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+        assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_eq_false() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 0);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+        assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_gt_true() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 0);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+        assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_gt_false() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+        assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_ge_true() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 0);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(1).build();
+
+        assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_ge_false() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GE, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+        assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_lt_true() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+        assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_lt_false() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(2).build();
+
+        assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_le_true() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(0).build();
+
+        assertTrue(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_int_le_false() {
+        IntAtomicFormula intAtomicFormula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LE, 1);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setVersionCode(2).build();
+
+        assertFalse(intAtomicFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_bool_true() {
+        BooleanAtomicFormula boolFormula =
+                new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setIsPreInstalled(true).build();
+
+        assertTrue(boolFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_bool_false() {
+        BooleanAtomicFormula boolFormula =
+                new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setIsPreInstalled(false).build();
+
+        assertFalse(boolFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testParcelUnparcel_string() {
+        StringAtomicFormula formula = new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "abc");
+        Parcel p = Parcel.obtain();
+        formula.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        StringAtomicFormula newFormula = StringAtomicFormula.CREATOR.createFromParcel(p);
+
+        assertEquals(formula, newFormula);
+    }
+
+    @Test
+    public void testParcelUnparcel_int() {
+        IntAtomicFormula formula =
+                new IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.LT, 1);
+        Parcel p = Parcel.obtain();
+        formula.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        IntAtomicFormula newFormula = IntAtomicFormula.CREATOR.createFromParcel(p);
+
+        assertEquals(formula, newFormula);
+    }
+
+    @Test
+    public void testParcelUnparcel_bool() {
+        BooleanAtomicFormula formula = new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
+        Parcel p = Parcel.obtain();
+        formula.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        BooleanAtomicFormula newFormula = BooleanAtomicFormula.CREATOR.createFromParcel(p);
+
+        assertEquals(formula, newFormula);
+    }
+
+    /** Returns a builder with all fields filled with some dummy data. */
+    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
+        return new AppInstallMetadata.Builder()
+                .setPackageName("abc")
+                .setAppCertificate("abc")
+                .setInstallerCertificate("abc")
+                .setInstallerName("abc")
+                .setVersionCode(-1)
+                .setIsPreInstalled(true);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
index 2133a7d..ecabb52 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/OpenFormulaTest.java
@@ -19,6 +19,10 @@
 import static com.android.server.testutils.TestUtils.assertExpectException;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -30,17 +34,17 @@
 @RunWith(JUnit4.class)
 public class OpenFormulaTest {
 
-    private static final AtomicFormula ATOMIC_FORMULA_1 = new AtomicFormula(
-            AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ, "test1");
-    private static final AtomicFormula ATOMIC_FORMULA_2 = new AtomicFormula(
-            AtomicFormula.Key.VERSION_CODE, AtomicFormula.Operator.EQ, 1);
+    private static final AtomicFormula ATOMIC_FORMULA_1 =
+            new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, "test1");
+    private static final AtomicFormula ATOMIC_FORMULA_2 =
+            new AtomicFormula.IntAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, 1);
 
     @Test
     public void testValidOpenFormula() {
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
-                Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
 
-        assertEquals(OpenFormula.Connector.AND, openFormula.getConnector());
+        assertEquals(OpenFormula.AND, openFormula.getConnector());
         assertEquals(Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2), openFormula.getFormulas());
     }
 
@@ -49,10 +53,10 @@
         assertExpectException(
                 IllegalArgumentException.class,
                 /* expectedExceptionMessageRegex */
-                String.format("Connector %s must have at least 2 formulas",
-                        OpenFormula.Connector.AND),
-                () -> new OpenFormula(OpenFormula.Connector.AND,
-                        Collections.singletonList(ATOMIC_FORMULA_1)));
+                String.format("Connector AND must have at least 2 formulas"),
+                () ->
+                        new OpenFormula(
+                                OpenFormula.AND, Collections.singletonList(ATOMIC_FORMULA_1)));
     }
 
     @Test
@@ -60,8 +64,159 @@
         assertExpectException(
                 IllegalArgumentException.class,
                 /* expectedExceptionMessageRegex */
-                String.format("Connector %s must have 1 formula only", OpenFormula.Connector.NOT),
-                () -> new OpenFormula(OpenFormula.Connector.NOT,
-                        Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+                String.format("Connector NOT must have 1 formula only"),
+                () ->
+                        new OpenFormula(
+                                OpenFormula.NOT,
+                                Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2)));
+    }
+
+    @Test
+    public void testIsSatisfiable_notFalse_true() {
+        OpenFormula openFormula = new OpenFormula(OpenFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test2").build();
+        // validate assumptions about the metadata
+        assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+
+        assertTrue(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_notTrue_false() {
+        OpenFormula openFormula = new OpenFormula(OpenFormula.NOT, Arrays.asList(ATOMIC_FORMULA_1));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test1").build();
+        // validate assumptions about the metadata
+        assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+
+        assertFalse(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_trueAndTrue_true() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
+        // validate assumptions about the metadata
+        assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertTrue(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_trueAndFalse_false() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
+        // validate assumptions about the metadata
+        assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertFalse(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_falseAndTrue_false() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
+        // validate assumptions about the metadata
+        assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertFalse(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_falseAndFalse_false() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
+        // validate assumptions about the metadata
+        assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertFalse(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_trueOrTrue_true() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(1).build();
+        // validate assumptions about the metadata
+        assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertTrue(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_trueOrFalse_true() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test1").setVersionCode(2).build();
+        // validate assumptions about the metadata
+        assertTrue(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertTrue(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_falseOrTrue_true() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(1).build();
+        // validate assumptions about the metadata
+        assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertTrue(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertTrue(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testIsSatisfiable_falseOrFalse_false() {
+        OpenFormula openFormula =
+                new OpenFormula(OpenFormula.OR, Arrays.asList(ATOMIC_FORMULA_1, ATOMIC_FORMULA_2));
+        AppInstallMetadata appInstallMetadata =
+                getAppInstallMetadataBuilder().setPackageName("test2").setVersionCode(2).build();
+        // validate assumptions about the metadata
+        assertFalse(ATOMIC_FORMULA_1.isSatisfied(appInstallMetadata));
+        assertFalse(ATOMIC_FORMULA_2.isSatisfied(appInstallMetadata));
+
+        assertFalse(openFormula.isSatisfied(appInstallMetadata));
+    }
+
+    @Test
+    public void testParcelUnparcel() {
+        OpenFormula formula =
+                new OpenFormula(OpenFormula.AND, Arrays.asList(ATOMIC_FORMULA_2, ATOMIC_FORMULA_1));
+        Parcel p = Parcel.obtain();
+        formula.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        OpenFormula newFormula = OpenFormula.CREATOR.createFromParcel(p);
+
+        assertEquals(formula, newFormula);
+    }
+
+    /** Returns a builder with all fields filled with some dummy data. */
+    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
+        return new AppInstallMetadata.Builder()
+                .setPackageName("abc")
+                .setAppCertificate("abc")
+                .setInstallerCertificate("abc")
+                .setInstallerName("abc")
+                .setVersionCode(-1)
+                .setIsPreInstalled(true);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
index 048ee70..e0c36fd 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/model/RuleTest.java
@@ -20,7 +20,8 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNull;
+
+import android.os.Parcel;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,23 +32,13 @@
 @RunWith(JUnit4.class)
 public class RuleTest {
 
-    private static final Rule.Effect DENY_EFFECT = Rule.Effect.DENY;
+    private static final @Rule.Effect int DENY_EFFECT = Rule.DENY;
     private static final String PACKAGE_NAME = "com.test.app";
     private static final String APP_CERTIFICATE = "test_cert";
     private static final Formula PACKAGE_NAME_ATOMIC_FORMULA =
-            new AtomicFormula(AtomicFormula.Key.PACKAGE_NAME, AtomicFormula.Operator.EQ,
-                    PACKAGE_NAME);
+            new AtomicFormula.StringAtomicFormula(AtomicFormula.PACKAGE_NAME, PACKAGE_NAME);
     private static final Formula APP_CERTIFICATE_ATOMIC_FORMULA =
-            new AtomicFormula(AtomicFormula.Key.APP_CERTIFICATE, AtomicFormula.Operator.EQ,
-                    APP_CERTIFICATE);
-
-    @Test
-    public void testEmptyRule() {
-        Rule emptyRule = Rule.EMPTY;
-
-        assertNull(emptyRule.getFormula());
-        assertNull(emptyRule.getEffect());
-    }
+            new AtomicFormula.StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, APP_CERTIFICATE);
 
     @Test
     public void testValidRule() {
@@ -58,14 +49,6 @@
     }
 
     @Test
-    public void testInvalidRule_invalidEffect() {
-        assertExpectException(
-                NullPointerException.class,
-                /* expectedExceptionMessageRegex */ null,
-                () -> new Rule(PACKAGE_NAME_ATOMIC_FORMULA, null));
-    }
-
-    @Test
     public void testInvalidRule_invalidFormula() {
         assertExpectException(
                 NullPointerException.class,
@@ -75,14 +58,17 @@
 
     @Test
     public void testToString() {
-        OpenFormula openFormula = new OpenFormula(OpenFormula.Connector.AND,
-                Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA, APP_CERTIFICATE_ATOMIC_FORMULA));
-        Rule rule = new Rule(openFormula, Rule.Effect.DENY);
+        OpenFormula openFormula =
+                new OpenFormula(
+                        OpenFormula.AND,
+                        Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA, APP_CERTIFICATE_ATOMIC_FORMULA));
+        Rule rule = new Rule(openFormula, Rule.DENY);
 
-        String toString = rule.toString();
-
-        assertEquals(String.format("Rule: PACKAGE_NAME EQ %s AND APP_CERTIFICATE EQ %s, DENY",
-                PACKAGE_NAME, APP_CERTIFICATE), toString);
+        assertEquals(
+                String.format(
+                        "Rule: (PACKAGE_NAME EQ %s) AND (APP_CERTIFICATE EQ %s), DENY",
+                        PACKAGE_NAME, APP_CERTIFICATE),
+                rule.toString());
     }
 
     @Test
@@ -100,4 +86,24 @@
 
         assertNotEquals(rule1, rule2);
     }
+
+    @Test
+    public void testParcelUnparcel() {
+        Rule rule =
+                new Rule(
+                        new OpenFormula(
+                                OpenFormula.AND,
+                                Arrays.asList(
+                                        APP_CERTIFICATE_ATOMIC_FORMULA,
+                                        new OpenFormula(
+                                                OpenFormula.NOT,
+                                                Arrays.asList(PACKAGE_NAME_ATOMIC_FORMULA)))),
+                        Rule.DENY);
+        Parcel p = Parcel.obtain();
+        rule.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        Rule newRule = Rule.CREATOR.createFromParcel(p);
+
+        assertEquals(newRule, rule);
+    }
 }
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
new file mode 100644
index 0000000..975689d
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/integrity/parser/RuleXmlParserTest.java
@@ -0,0 +1,445 @@
+/*
+ * 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 static com.android.server.testutils.TestUtils.assertExpectException;
+
+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;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+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 {
+
+    @Test
+    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();
+        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);
+
+        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 = "<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(
+                RuleParseException.class,
+                /* expectedExceptionMessageRegex */ "Rules must start with RuleList <RL> tag",
+                () -> xmlParser.parse(ruleXmlWithNoRuleList));
+    }
+
+    @Test
+    public void testXmlStream_withNoRuleList() {
+        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(
+                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/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
index bcff2f8..608625f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryDatabaseTest.java
@@ -18,6 +18,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -25,7 +26,9 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AlarmManager;
 import android.app.NotificationHistory.HistoricalNotification;
+import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.os.Handler;
 import android.util.AtomicFile;
@@ -42,8 +45,17 @@
 import org.mockito.MockitoAnnotations;
 
 import java.io.File;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileTime;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 @RunWith(AndroidJUnit4.class)
 public class NotificationHistoryDatabaseTest extends UiServiceTestCase {
@@ -51,6 +63,11 @@
     File mRootDir;
     @Mock
     Handler mFileWriteHandler;
+    @Mock
+    Context mContext;
+    @Mock
+    AlarmManager mAlarmManager;
+    TestFileAttrProvider mFileAttrProvider;
 
     NotificationHistoryDatabase mDataBase;
 
@@ -85,36 +102,56 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(AlarmManager.class)).thenReturn(mAlarmManager);
+        when(mContext.getUser()).thenReturn(getContext().getUser());
+        when(mContext.getPackageName()).thenReturn(getContext().getPackageName());
 
+        mFileAttrProvider = new TestFileAttrProvider();
         mRootDir = new File(mContext.getFilesDir(), "NotificationHistoryDatabaseTest");
 
-        mDataBase = new NotificationHistoryDatabase(mRootDir);
+        mDataBase = new NotificationHistoryDatabase(mContext, mRootDir, mFileAttrProvider);
         mDataBase.init(mFileWriteHandler);
     }
 
     @Test
-    public void testPrune() {
+    public void testDeletionReceiver() {
+        verify(mContext, times(1)).registerReceiver(any(), any());
+    }
+
+    @Test
+    public void testPrune() throws Exception {
+        GregorianCalendar cal = new GregorianCalendar();
+        cal.setTimeInMillis(10);
         int retainDays = 1;
-        for (long i = 10; i >= 5; i--) {
+
+        List<AtomicFile> expectedFiles = new ArrayList<>();
+
+        // add 5 files with a creation date of "today"
+        for (long i = cal.getTimeInMillis(); i >= 5; i--) {
             File file = mock(File.class);
-            when(file.lastModified()).thenReturn(i);
+            mFileAttrProvider.creationDates.put(file, i);
             AtomicFile af = new AtomicFile(file);
+            expectedFiles.add(af);
             mDataBase.mHistoryFiles.addLast(af);
         }
-        GregorianCalendar cal = new GregorianCalendar();
-        cal.setTimeInMillis(5);
+
         cal.add(Calendar.DATE, -1 * retainDays);
+        // Add 5 more files more than retainDays old
         for (int i = 5; i >= 0; i--) {
             File file = mock(File.class);
-            when(file.lastModified()).thenReturn(cal.getTimeInMillis() - i);
+            mFileAttrProvider.creationDates.put(file, cal.getTimeInMillis() - i);
             AtomicFile af = new AtomicFile(file);
             mDataBase.mHistoryFiles.addLast(af);
         }
-        mDataBase.prune(retainDays, 10);
 
-        for (AtomicFile file : mDataBase.mHistoryFiles) {
-            assertThat(file.getBaseFile().lastModified() > 0);
-        }
+        // back to today; trim everything a day + old
+        cal.add(Calendar.DATE, 1 * retainDays);
+        mDataBase.prune(retainDays, cal.getTimeInMillis());
+
+        assertThat(mDataBase.mHistoryFiles).containsExactlyElementsIn(expectedFiles);
+
+        verify(mAlarmManager, times(6)).setExactAndAllowWhileIdle(anyInt(), anyLong(), any());
+
     }
 
     @Test
@@ -181,4 +218,12 @@
         verify(af2, never()).openRead();
     }
 
+    private class TestFileAttrProvider implements NotificationHistoryDatabase.FileAttrProvider {
+        public Map<File, Long> creationDates = new HashMap<>();
+
+        @Override
+        public long getCreationTime(File file) {
+            return creationDates.get(file);
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
deleted file mode 100644
index 20d7a2a..0000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationStatsTest.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/**
- * Copyright (c) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.server.notification;
-
-import static android.service.notification.NotificationStats.DISMISSAL_PEEK;
-import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEGATIVE;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-
-import android.os.Parcel;
-import android.service.notification.NotificationStats;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.server.UiServiceTestCase;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NotificationStatsTest extends UiServiceTestCase {
-
-    @Test
-    public void testConstructor() {
-        NotificationStats stats = new NotificationStats();
-
-        assertFalse(stats.hasSeen());
-        assertFalse(stats.hasDirectReplied());
-        assertFalse(stats.hasExpanded());
-        assertFalse(stats.hasInteracted());
-        assertFalse(stats.hasViewedSettings());
-        assertFalse(stats.hasSnoozed());
-        assertEquals(NotificationStats.DISMISSAL_NOT_DISMISSED, stats.getDismissalSurface());
-        assertEquals(NotificationStats.DISMISS_SENTIMENT_UNKNOWN, stats.getDismissalSentiment());
-    }
-
-    @Test
-    public void testSeen() {
-        NotificationStats stats = new NotificationStats();
-        stats.setSeen();
-        assertTrue(stats.hasSeen());
-        assertFalse(stats.hasInteracted());
-    }
-
-    @Test
-    public void testDirectReplied() {
-        NotificationStats stats = new NotificationStats();
-        stats.setDirectReplied();
-        assertTrue(stats.hasDirectReplied());
-        assertTrue(stats.hasInteracted());
-    }
-
-    @Test
-    public void testExpanded() {
-        NotificationStats stats = new NotificationStats();
-        stats.setExpanded();
-        assertTrue(stats.hasExpanded());
-        assertTrue(stats.hasInteracted());
-    }
-
-    @Test
-    public void testSnoozed() {
-        NotificationStats stats = new NotificationStats();
-        stats.setSnoozed();
-        assertTrue(stats.hasSnoozed());
-        assertTrue(stats.hasInteracted());
-    }
-
-    @Test
-    public void testViewedSettings() {
-        NotificationStats stats = new NotificationStats();
-        stats.setViewedSettings();
-        assertTrue(stats.hasViewedSettings());
-        assertTrue(stats.hasInteracted());
-    }
-
-    @Test
-    public void testDismissalSurface() {
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSurface(DISMISSAL_PEEK);
-        assertEquals(DISMISSAL_PEEK, stats.getDismissalSurface());
-        assertFalse(stats.hasInteracted());
-    }
-
-    @Test
-    public void testDismissalSentiment() {
-        NotificationStats stats = new NotificationStats();
-        stats.setDismissalSentiment(DISMISS_SENTIMENT_NEGATIVE);
-        assertEquals(DISMISS_SENTIMENT_NEGATIVE, stats.getDismissalSentiment());
-        assertFalse(stats.hasInteracted());
-    }
-
-    @Test
-    public void testWriteToParcel() {
-        NotificationStats stats = new NotificationStats();
-        stats.setViewedSettings();
-        stats.setDismissalSurface(NotificationStats.DISMISSAL_AOD);
-        stats.setDismissalSentiment(NotificationStats.DISMISS_SENTIMENT_POSITIVE);
-        Parcel parcel = Parcel.obtain();
-        stats.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-        NotificationStats stats1 = NotificationStats.CREATOR.createFromParcel(parcel);
-        assertEquals(stats, stats1);
-    }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index a1322b9..8961796 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -2417,6 +2417,24 @@
     }
 
     @Test
+    public void testLockChannelsForOEM_channelSpecific_clearData() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        mHelper.getImportance(PKG_O, UID_O);
+        mHelper.lockChannelsForOEM(new String[] {PKG_O + ":" + a.getId()});
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByOEM());
+
+        mHelper.clearData(PKG_O, UID_O);
+
+        // it's back!
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        // and still locked
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByOEM());
+    }
+
+    @Test
     public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
         NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
         NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
@@ -2715,4 +2733,57 @@
         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true));
         assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true));
     }
+
+    @Test
+    public void testRestoreMultiUser() throws Exception {
+        String pkg = "restore_pkg";
+        String channelId = "channelId";
+        int user0Importance = 3;
+        int user10Importance = 4;
+        when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL);
+
+        // both users have the same package, but different notification settings
+        final String xmlUser0 = "<ranking version=\"1\">\n"
+                + "<package name=\"" + pkg + "\" >\n"
+                + "<channel id=\"" + channelId + "\" name=\"hi\""
+                + " importance=\"" + user0Importance + "\"/>"
+                + "</package>"
+                + "</ranking>";
+        final String xmlUser10 = "<ranking version=\"1\">\n"
+                + "<package name=\"" + pkg + "\" >\n"
+                + "<channel id=\"" + channelId + "\" name=\"hi\""
+                + " importance=\"" + user10Importance + "\"/>"
+                + "</package>"
+                + "</ranking>";
+
+        // trigger a restore for both users
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, true, 0);
+        parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())),
+                null);
+        parser.nextTag();
+        mHelper.readXml(parser, true, 10);
+
+        // "install" package on both users
+        String[] pkgList = new String[] {pkg};
+        int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE};
+        int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1};
+        when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]);
+        when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]);
+        ApplicationInfo info = new ApplicationInfo();
+        info.targetSdkVersion = Build.VERSION_CODES.Q;
+        when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info);
+
+        mHelper.onPackagesChanged(false, 0, pkgList, uidList0);
+        mHelper.onPackagesChanged(false, 10, pkgList, uidList10);
+
+        assertEquals(user0Importance,
+                mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance());
+        assertEquals(user10Importance, mHelper.getNotificationChannel(
+                pkg, uidList10[0], channelId, false).getImportance());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 3d87223..b654764 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -99,7 +99,7 @@
         suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
 
         Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders,
-                priorityMessageSenders, suppressedVisualEffects);
+                priorityMessageSenders, suppressedVisualEffects, 0);
 
         assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy));
     }
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 4daf6d3..9df7b45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -93,7 +93,7 @@
         // Create a pinned stack and move to front.
         final ActivityStack pinnedStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final TaskRecord pinnedTask = new TaskBuilder(mService.mStackSupervisor)
+        final Task pinnedTask = new TaskBuilder(mService.mStackSupervisor)
                 .setStack(pinnedStack).build();
         new ActivityBuilder(mService).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
                 .setTask(pinnedTask).build();
@@ -167,7 +167,7 @@
     private ActivityStack createFullscreenStackWithSimpleActivityAt(ActivityDisplay display) {
         final ActivityStack fullscreenStack = display.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final TaskRecord fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
+        final Task fullscreenTask = new TaskBuilder(mService.mStackSupervisor)
                 .setStack(fullscreenStack).build();
         new ActivityBuilder(mService).setTask(fullscreenTask).build();
         return fullscreenStack;
@@ -302,18 +302,10 @@
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
         final ActivityStack stack4 = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, ON_TOP);
-        final TaskRecord task1 = new TaskBuilder(mService.mStackSupervisor)
-                .setStack(stack1)
-                .build();
-        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
-                .setStack(stack2)
-                .build();
-        final TaskRecord task3 = new TaskBuilder(mService.mStackSupervisor)
-                .setStack(stack3)
-                .build();
-        final TaskRecord task4 = new TaskBuilder(mService.mStackSupervisor)
-                .setStack(stack4)
-                .build();
+        final Task task1 = new TaskBuilder(mService.mStackSupervisor).setStack(stack1).build();
+        final Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(stack2).build();
+        final Task task3 = new TaskBuilder(mService.mStackSupervisor).setStack(stack3).build();
+        final Task task4 = new TaskBuilder(mService.mStackSupervisor).setStack(stack4).build();
 
         // Reordering stacks while removing stacks.
         doAnswer(invocation -> {
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 44cacd8..3c619f7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -78,7 +78,7 @@
         // This seems to be the easiest way to create an ActivityRecord.
         mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
         mTopActivity = new ActivityBuilder(mService)
-                .setTask(mTrampolineActivity.getTaskRecord())
+                .setTask(mTrampolineActivity.getTask())
                 .build();
     }
 
@@ -177,7 +177,7 @@
         mSupervisor.beginDeferResume();
         // Create an activity with different process that meets process switch.
         final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
-                .setTask(mTopActivity.getTaskRecord())
+                .setTask(mTopActivity.getTask())
                 .setProcessName("other")
                 .build();
         mSupervisor.readyToResume();
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 2ce37f1..c51a46a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -113,7 +113,7 @@
 @RunWith(WindowTestRunner.class)
 public class ActivityRecordTests extends ActivityTestsBase {
     private ActivityStack mStack;
-    private TaskRecord mTask;
+    private Task mTask;
     private ActivityRecord mActivity;
 
     @Before
@@ -147,7 +147,7 @@
 
     @Test
     public void testNoCleanupMovingActivityInSameStack() {
-        final TaskRecord newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
+        final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack)
                 .build();
         mActivity.reparent(newTask, 0, null /*reason*/);
         verify(mStack, times(0)).onActivityRemovedFromStack(any());
@@ -255,7 +255,7 @@
 
         // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options.
         // Pending options should be cleared for only ActivityRecord that was applied
-        TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
         activity2 = new ActivityBuilder(mService).setTask(task2).build();
         activity2.updateOptionsLocked(activityOptions);
         mActivity.updateOptionsLocked(activityOptions);
@@ -595,7 +595,7 @@
         final int originalDpi = mActivity.getConfiguration().densityDpi;
 
         // Move the non-resizable activity to the new display.
-        mStack.reparent(newDisplay, true /* onTop */, false /* displayRemoved */);
+        mStack.reparent(newDisplay.mDisplayContent, true /* onTop */);
 
         assertEquals(originalBounds.width(),
                 mActivity.getWindowConfiguration().getBounds().width());
@@ -1171,7 +1171,7 @@
     public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() {
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
-        for (TaskRecord t : homeStack.getAllTasks()) {
+        for (Task t : homeStack.getAllTasks()) {
             homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
@@ -1197,7 +1197,7 @@
     public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() {
         // Empty the home stack.
         final ActivityStack homeStack = mActivity.getDisplay().getHomeStack();
-        for (TaskRecord t : homeStack.getAllTasks()) {
+        for (Task t : homeStack.getAllTasks()) {
             homeStack.removeChild(t, "test");
         }
         mActivity.finishing = true;
@@ -1244,12 +1244,12 @@
     public void testDestroyImmediately_noApp_finishing() {
         mActivity.app = null;
         mActivity.finishing = true;
-        final TaskRecord task = mActivity.getTaskRecord();
+        final Task task = mActivity.getTask();
 
         mActivity.destroyImmediately(false /* removeFromApp */, "test");
 
         assertEquals(DESTROYED, mActivity.getState());
-        assertNull(mActivity.getTaskRecord());
+        assertNull(mActivity.getTask());
         assertEquals(0, task.getChildCount());
     }
 
@@ -1261,12 +1261,12 @@
     public void testDestroyImmediately_noApp_notFinishing() {
         mActivity.app = null;
         mActivity.finishing = false;
-        final TaskRecord task = mActivity.getTaskRecord();
+        final Task task = mActivity.getTask();
 
         mActivity.destroyImmediately(false /* removeFromApp */, "test");
 
         assertEquals(DESTROYED, mActivity.getState());
-        assertEquals(task, mActivity.getTaskRecord());
+        assertEquals(task, mActivity.getTask());
         assertEquals(1, task.getChildCount());
     }
 
@@ -1297,13 +1297,13 @@
     @Test
     public void testRemoveFromHistory() {
         final ActivityStack stack = mActivity.getActivityStack();
-        final TaskRecord task = mActivity.getTaskRecord();
+        final Task task = mActivity.getTask();
 
         mActivity.removeFromHistory("test");
 
         assertEquals(DESTROYED, mActivity.getState());
         assertNull(mActivity.app);
-        assertNull(mActivity.getTaskRecord());
+        assertNull(mActivity.getTask());
         assertEquals(0, task.getChildCount());
         assertNull(task.getStack());
         assertEquals(0, stack.getChildCount());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index 1eeca91..128ed2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -116,7 +116,7 @@
         final ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setDisplay(newDisplay).build();
         final ActivityRecord unresizableActivity = stack.getTopActivity();
-        final TaskRecord task = unresizableActivity.getTaskRecord();
+        final Task task = unresizableActivity.getTask();
         unresizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
         task.setResizeMode(unresizableActivity.info.resizeMode);
 
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 cc0cc3f..d0e07b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -43,7 +43,7 @@
 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
-import static com.android.server.wm.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
+import static com.android.server.wm.Task.REPARENT_MOVE_STACK_TO_FRONT;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -80,7 +80,7 @@
 public class ActivityStackTests extends ActivityTestsBase {
     private ActivityDisplay mDefaultDisplay;
     private ActivityStack mStack;
-    private TaskRecord mTask;
+    private Task mTask;
 
     @Before
     public void setUp() throws Exception {
@@ -111,7 +111,7 @@
         final ActivityStack destStack = mRootActivityContainer.getDefaultDisplay().createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        mTask.reparent(destStack, true /* toTop */, TaskRecord.REPARENT_KEEP_STACK_AT_FRONT,
+        mTask.reparent(destStack, true /* toTop */, Task.REPARENT_KEEP_STACK_AT_FRONT,
                 false /* animate */, true /* deferResume*/,
                 "testResumedActivityFromTaskReparenting");
 
@@ -233,7 +233,7 @@
                 .setStack(mStack)
                 .setUid(0)
                 .build();
-        final TaskRecord task = r.getTaskRecord();
+        final Task task = r.getTask();
         // Overlay must be for a different user to prevent recognizing a matching top activity
         final ActivityRecord taskOverlay = new ActivityBuilder(mService).setTask(task)
                 .setUid(UserHandle.PER_USER_RANGE * 2).build();
@@ -256,7 +256,7 @@
                 targetActivity);
         final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
                 aliasActivity);
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build();
         task.origActivity = alias;
         task.realActivity = target;
         new ActivityBuilder(mService).setComponent(target).setTask(task).setTargetActivity(
@@ -287,14 +287,12 @@
 
         // Do not move display to back because there is still another stack.
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
-                eq(false) /* includingParents */);
+        verify(stack2).positionChildAtBottom(any(), eq(false) /* includingParents */);
 
         // Also move display to back because there is only one stack left.
         display.removeChild(stack1);
         stack2.moveToBack("testMoveStackToBackIncludingParent", stack2.topTask());
-        verify(stack2.getTaskStack()).positionChildAtBottom(any(),
-                eq(true) /* includingParents */);
+        verify(stack2).positionChildAtBottom(any(), eq(true) /* includingParents */);
     }
 
     @Test
@@ -1093,7 +1091,7 @@
     public void testResetTaskWithFinishingActivities() {
         final ActivityRecord taskTop =
                 new ActivityBuilder(mService).setStack(mStack).setCreateTask(true).build();
-        // Make all activities in the task are finishing to simulate TaskRecord#getTopActivity
+        // Make all activities in the task are finishing to simulate Task#getTopActivity
         // returns null.
         taskTop.finishing = true;
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index a28bbb6..9af90e3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -132,7 +132,7 @@
     @Test
     public void testUpdateLaunchBounds() {
         // When in a non-resizeable stack, the task bounds should be updated.
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
+        final Task task = new TaskBuilder(mService.mStackSupervisor)
                 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
                 .build();
@@ -143,7 +143,7 @@
         assertEquals(new Rect(), task.getStack().getRequestedOverrideBounds());
 
         // When in a resizeable stack, the stack bounds should be updated as well.
-        final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
+        final Task task2 = new TaskBuilder(mService.mStackSupervisor)
                 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
                 .build();
@@ -712,10 +712,10 @@
         verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
 
         final ActivityRecord startedActivity = outActivity[0];
-        if (startedActivity != null && startedActivity.getTaskRecord() != null) {
+        if (startedActivity != null && startedActivity.getTask() != null) {
             // Remove the activity so it doesn't interfere with with subsequent activity launch
             // tests from this method.
-            startedActivity.getTaskRecord().removeChild(startedActivity);
+            startedActivity.getTask().removeChild(startedActivity);
         }
     }
 
@@ -807,7 +807,7 @@
         // Create another activity on top of the secondary display.
         final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
+        final Task topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
         new ActivityBuilder(mService).setTask(topTask).build();
 
         // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
@@ -829,14 +829,14 @@
         final ComponentName componentName = ComponentName.createRelative(
                 DEFAULT_COMPONENT_PACKAGE_NAME,
                 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
-        final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
+        final Task task = new TaskBuilder(mSupervisor)
                 .setComponent(componentName)
                 .setStack(stack)
                 .build();
         return new ActivityBuilder(mService)
                 .setComponent(componentName)
                 .setLaunchMode(LAUNCH_SINGLE_TASK)
-                .setTask(taskRecord)
+                .setTask(task)
                 .build();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 399f283..39aa51a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -69,7 +69,7 @@
         removeGlobalMinSizeRestriction();
         final ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
-        final TaskRecord task = stack.topTask();
+        final Task task = stack.topTask();
         WindowContainerTransaction t = new WindowContainerTransaction();
         Rect newBounds = new Rect(10, 10, 100, 100);
         t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
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 1db8f1b..47b39b0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -117,7 +117,7 @@
 
         private ComponentName mComponent;
         private String mTargetActivity;
-        private TaskRecord mTaskRecord;
+        private Task mTask;
         private String mProcessName = "name";
         private int mUid = 12345;
         private boolean mCreateTask;
@@ -151,8 +151,8 @@
                     DEFAULT_COMPONENT_PACKAGE_NAME);
         }
 
-        ActivityBuilder setTask(TaskRecord task) {
-            mTaskRecord = task;
+        ActivityBuilder setTask(Task task) {
+            mTask = task;
             return this;
         }
 
@@ -229,7 +229,7 @@
             }
 
             if (mCreateTask) {
-                mTaskRecord = new TaskBuilder(mService.mStackSupervisor)
+                mTask = new TaskBuilder(mService.mStackSupervisor)
                         .setComponent(mComponent)
                         .setStack(mStack).build();
             }
@@ -265,11 +265,11 @@
                     false /* rootVoiceInteraction */, mService.mStackSupervisor, options,
                     null /* sourceRecord */);
             spyOn(activity);
-            if (mTaskRecord != null) {
+            if (mTask != null) {
                 // fullscreen value is normally read from resources in ctor, so for testing we need
                 // to set it somewhere else since we can't mock resources.
                 doReturn(true).when(activity).occludesParent();
-                mTaskRecord.addChild(activity);
+                mTask.addChild(activity);
                 // Make visible by default...
                 activity.setHidden(false);
             }
@@ -354,7 +354,7 @@
             return this;
         }
 
-        TaskRecord build() {
+        Task build() {
             if (mStack == null && mCreateStack) {
                 mStack = mSupervisor.mRootActivityContainer.getDefaultDisplay().createStack(
                         WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -374,7 +374,7 @@
             intent.setComponent(mComponent);
             intent.setFlags(mFlags);
 
-            final TaskRecord task = new TaskRecord(mSupervisor.mService, mTaskId, aInfo,
+            final Task task = new Task(mSupervisor.mService, mTaskId, aInfo,
                     intent /*intent*/, mVoiceSession, null /*_voiceInteractor*/,
                     null /*taskDescription*/, mStack);
             spyOn(task);
@@ -462,7 +462,6 @@
             }
 
             spyOn(stack);
-            spyOn(stack.mTaskStack);
             doNothing().when(stack).startActivityLocked(
                     any(), any(), anyBoolean(), anyBoolean(), any());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index b6eaab7..c6203c5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -37,7 +37,7 @@
 import org.mockito.MockitoAnnotations;
 
 /**
- * Tests for the {@link TaskStack} class.
+ * Tests for the {@link ActivityStack} class.
  *
  * Build/Install/Run:
  *  atest FrameworksServicesTests:AnimatingActivityRegistryTest
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 7b9be3d..fc94c5e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -28,7 +28,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
-import android.graphics.Rect;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 import android.view.Display;
@@ -55,7 +54,7 @@
 @RunWith(WindowTestRunner.class)
 public class AppChangeTransitionTests extends WindowTestsBase {
 
-    private TaskStack mStack;
+    private ActivityStack mStack;
     private Task mTask;
     private ActivityRecord mActivity;
 
@@ -148,7 +147,7 @@
         // Reparenting to a display with different windowing mode may trigger
         // a change transition internally, but it should be cleaned-up once
         // the display change is complete.
-        mStack.reparent(mDisplayContent.getDisplayId(), new Rect(), true);
+        mStack.reparent(mDisplayContent, true);
 
         assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 5f42d23..c71d819 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -157,7 +157,7 @@
         final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
         final DisplayContent dc2 = createNewDisplay(Display.STATE_ON);
 
-        final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+        final ActivityStack stack1 = createTaskStackOnDisplay(dc1);
         final Task task1 = createTaskInStack(stack1, 0 /* userId */);
         final ActivityRecord activity1 =
                 WindowTestUtils.createTestActivityRecord(dc1);
@@ -176,7 +176,7 @@
         assertTrue(dc1.mOpeningApps.size() > 0);
 
         // Move stack to another display.
-        stack1.reparent(dc2.getDisplayId(),  new Rect(), true);
+        stack1.reparent(dc2, true);
 
         // Verify if token are cleared from both pending transition list in former display.
         assertFalse(dc1.mOpeningApps.contains(activity1));
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 d33dbd1..bd336ad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -75,7 +75,7 @@
 @RunWith(WindowTestRunner.class)
 public class AppWindowTokenTests extends WindowTestsBase {
 
-    TaskStack mStack;
+    ActivityStack mStack;
     Task mTask;
     ActivityRecord mActivity;
 
@@ -208,11 +208,9 @@
 
     @Test
     public void testSizeCompatBounds() {
-        // TODO(task-merge): Move once Task is merged into TaskRecord
-        final TaskRecord tr = (TaskRecord) mTask;
         // Disable the real configuration resolving because we only simulate partial flow.
         // TODO: Have test use full flow.
-        doNothing().when(tr).computeConfigResourceOverrides(any(), any());
+        doNothing().when(mTask).computeConfigResourceOverrides(any(), any());
         final Rect fixedBounds = mActivity.getRequestedOverrideConfiguration().windowConfiguration
                 .getBounds();
         fixedBounds.set(0, 0, 1200, 1600);
@@ -411,7 +409,7 @@
     }
 
     private ActivityRecord createIsolatedTestActivityRecord() {
-        final TaskStack taskStack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(taskStack, 0 /* userId */);
         return createTestActivityRecordForGivenTask(task);
     }
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 bd137fb..9f4143f 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;
@@ -235,7 +240,7 @@
         final DisplayContent dc = createNewDisplay();
 
         // Add stack with activity.
-        final TaskStack stack = createTaskStackOnDisplay(dc);
+        final ActivityStack stack = createTaskStackOnDisplay(dc);
         assertEquals(dc.getDisplayId(), stack.getDisplayContent().getDisplayId());
         assertEquals(dc, stack.getParent().getParent());
         assertEquals(dc, stack.getDisplayContent());
@@ -311,7 +316,7 @@
         final DisplayContent dc1 = createNewDisplay();
 
         // Add stack with activity.
-        final TaskStack stack0 = createTaskStackOnDisplay(dc0);
+        final ActivityStack stack0 = createTaskStackOnDisplay(dc0);
         final Task task0 = createTaskInStack(stack0, 0 /* userId */);
         final ActivityRecord activity =
                 WindowTestUtils.createTestActivityRecord(dc0);
@@ -319,7 +324,7 @@
         dc0.configureDisplayPolicy();
         assertNotNull(dc0.mTapDetector);
 
-        final TaskStack stack1 = createTaskStackOnDisplay(dc1);
+        final ActivityStack stack1 = createTaskStackOnDisplay(dc1);
         final Task task1 = createTaskInStack(stack1, 0 /* userId */);
         final ActivityRecord activity1 =
                 WindowTestUtils.createTestActivityRecord(dc0);
@@ -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/DragDropControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
index bfb4607..5acc0f2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DragDropControllerTests.java
@@ -98,7 +98,7 @@
     private WindowState createDropTargetWindow(String name, int ownerId) {
         final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(
                 mDisplayContent);
-        final TaskStack stack = createTaskStackOnDisplay(
+        final ActivityStack stack = createTaskStackOnDisplay(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent);
         final Task task = createTaskInStack(stack, ownerId);
         task.addChild(activity, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 46435eb..31b658a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -89,9 +89,9 @@
         final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
         final ActivityOptions options = mock(ActivityOptions.class);
 
-        mController.calculate(record.getTaskRecord(), layout, record, source, options, PHASE_BOUNDS,
+        mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
                 new LaunchParams());
-        verify(positioner, times(1)).onCalculate(eq(record.getTaskRecord()), eq(layout), eq(record),
+        verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
                 eq(source), eq(options), anyInt(), any(), any());
     }
 
@@ -114,7 +114,7 @@
 
         mPersister.putLaunchParams(userId, name, expected);
 
-        mController.calculate(activity.getTaskRecord(), null /*layout*/, activity, null /*source*/,
+        mController.calculate(activity.getTask(), null /*layout*/, activity, null /*source*/,
                 null /*options*/, PHASE_BOUNDS, new LaunchParams());
         verify(positioner, times(1)).onCalculate(any(), any(), any(), any(), any(), anyInt(),
                 eq(expected), any());
@@ -263,9 +263,9 @@
         final WindowLayout layout = new WindowLayout(0, 0, 0, 0, 0, 0, 0);
         final ActivityOptions options = mock(ActivityOptions.class);
 
-        mController.calculate(record.getTaskRecord(), layout, record, source, options, PHASE_BOUNDS,
+        mController.calculate(record.getTask(), layout, record, source, options, PHASE_BOUNDS,
                 new LaunchParams());
-        verify(positioner, times(1)).onCalculate(eq(record.getTaskRecord()), eq(layout), eq(record),
+        verify(positioner, times(1)).onCalculate(eq(record.getTask()), eq(layout), eq(record),
                 eq(source), eq(options), eq(PHASE_BOUNDS), any(), any());
     }
 
@@ -278,7 +278,7 @@
         final LaunchParams params = new LaunchParams();
         params.mPreferredDisplayId = 2;
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -298,7 +298,7 @@
         final int windowingMode = WINDOWING_MODE_FREEFORM;
         params.mWindowingMode = windowingMode;
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -323,7 +323,7 @@
         params.mWindowingMode = WINDOWING_MODE_FREEFORM;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -331,7 +331,7 @@
 
         mController.layoutTask(task, null /* windowLayout */);
 
-        // TaskRecord will make adjustments to requested bounds. We only need to guarantee that the
+        // Task will make adjustments to requested bounds. We only need to guarantee that the
         // reuqested bounds are expected.
         assertEquals(expected, task.getRequestedOverrideBounds());
     }
@@ -348,7 +348,7 @@
         params.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
         params.mBounds.set(expected);
         final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params);
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor).build();
+        final Task task = new TaskBuilder(mService.mStackSupervisor).build();
 
         mController.registerModifier(positioner);
 
@@ -371,7 +371,7 @@
         }
 
         @Override
-        public int onCalculate(TaskRecord task, WindowLayout layout, ActivityRecord activity,
+        public int onCalculate(Task task, WindowLayout layout, ActivityRecord activity,
                    ActivityRecord source, ActivityOptions options, int phase,
                    LaunchParams currentParams, LaunchParams outParams) {
             outParams.set(mParams);
@@ -421,7 +421,7 @@
         }
 
         @Override
-        void saveTask(TaskRecord task) {
+        void saveTask(Task task) {
             final int userId = task.mUserId;
             final ComponentName realActivity = task.realActivity;
             mTmpParams.mPreferredDisplayId = task.getStack().mDisplayId;
@@ -435,7 +435,7 @@
         }
 
         @Override
-        void getLaunchParams(TaskRecord task, ActivityRecord activity, LaunchParams params) {
+        void getLaunchParams(Task task, ActivityRecord activity, LaunchParams params) {
             final int userId = task != null ? task.mUserId : activity.mUserId;
             final ComponentName name = task != null
                     ? task.realActivity : activity.mActivityComponent;
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index b9fef4b..0908f71 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -81,9 +81,9 @@
     private File mFolder;
     private ActivityDisplay mTestDisplay;
     private String mDisplayUniqueId;
-    private TaskRecord mTestTask;
-    private TaskRecord mTaskWithDifferentUser;
-    private TaskRecord mTaskWithDifferentComponent;
+    private Task mTestTask;
+    private Task mTaskWithDifferentUser;
+    private Task mTaskWithDifferentComponent;
     private PackageManagerInternal mMockPmi;
     private PackageManagerInternal.PackageListObserver mObserver;
 
@@ -234,7 +234,7 @@
 
         ActivityStack stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
                 ACTIVITY_TYPE_STANDARD, /* onTop */ true);
-        final TaskRecord anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
+        final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
                 .setComponent(ALTERNATIVE_COMPONENT)
                 .setUserId(TEST_USER_ID)
                 .setStack(stack)
@@ -246,7 +246,7 @@
 
         stack = mTestDisplay.createStack(TEST_WINDOWING_MODE,
                 ACTIVITY_TYPE_STANDARD, /* onTop */ true);
-        final TaskRecord anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
+        final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
                 .setComponent(TEST_COMPONENT)
                 .setUserId(ALTERNATIVE_USER_ID)
                 .setStack(stack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
index 05e173c..6ced816 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LockTaskControllerTest.java
@@ -165,7 +165,7 @@
     @Test
     public void testStartLockTaskMode_once() throws Exception {
         // GIVEN a task record with whitelisted auth
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
 
         // WHEN calling setLockTaskMode for LOCKED mode without resuming
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -182,8 +182,8 @@
     @Test
     public void testStartLockTaskMode_twice() throws Exception {
         // GIVEN two task records with whitelisted auth
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
-        TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
 
         // WHEN calling setLockTaskMode for LOCKED mode on both tasks
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
@@ -202,7 +202,7 @@
     @Test
     public void testStartLockTaskMode_pinningRequest() {
         // GIVEN a task record that is not whitelisted, i.e. with pinned auth
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
 
         // WHEN calling startLockTaskMode
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
@@ -214,7 +214,7 @@
     @Test
     public void testStartLockTaskMode_pinnedBySystem() throws Exception {
         // GIVEN a task record with pinned auth
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
 
         // WHEN the system calls startLockTaskMode
         mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
@@ -233,41 +233,41 @@
     @Test
     public void testLockTaskViolation() {
         // GIVEN one task record with whitelisted auth that is in lock task mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN it's not a lock task violation to try and launch this task without clearing
         assertFalse(mLockTaskController.isLockTaskModeViolation(tr, false));
 
         // THEN it's a lock task violation to launch another task that is not whitelisted
-        assertTrue(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
-                TaskRecord.LOCK_TASK_AUTH_PINNABLE)));
+        assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
+                Task.LOCK_TASK_AUTH_PINNABLE)));
         // THEN it's a lock task violation to launch another task that is disallowed from lock task
-        assertTrue(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
-                TaskRecord.LOCK_TASK_AUTH_DONT_LOCK)));
+        assertTrue(mLockTaskController.isLockTaskModeViolation(getTask(
+                Task.LOCK_TASK_AUTH_DONT_LOCK)));
 
         // THEN it's no a lock task violation to launch another task that is whitelisted
-        assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
-                TaskRecord.LOCK_TASK_AUTH_WHITELISTED)));
-        assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
-                TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE)));
+        assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+                Task.LOCK_TASK_AUTH_WHITELISTED)));
+        assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+                Task.LOCK_TASK_AUTH_LAUNCHABLE)));
         // THEN it's not a lock task violation to launch another task that is priv launchable
-        assertFalse(mLockTaskController.isLockTaskModeViolation(getTaskRecord(
-                TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
+        assertFalse(mLockTaskController.isLockTaskModeViolation(getTask(
+                Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV)));
     }
 
     @Test
     public void testLockTaskViolation_emergencyCall() {
         // GIVEN one task record with whitelisted auth that is in lock task mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // GIVEN tasks necessary for emergency calling
-        TaskRecord keypad = getTaskRecord(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
-                TaskRecord.LOCK_TASK_AUTH_PINNABLE);
-        TaskRecord callAction = getTaskRecord(new Intent(Intent.ACTION_CALL_EMERGENCY),
-                TaskRecord.LOCK_TASK_AUTH_PINNABLE);
-        TaskRecord dialer = getTaskRecord("com.example.dialer", TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+        Task keypad = getTask(new Intent().setComponent(EMERGENCY_DIALER_COMPONENT),
+                Task.LOCK_TASK_AUTH_PINNABLE);
+        Task callAction = getTask(new Intent(Intent.ACTION_CALL_EMERGENCY),
+                Task.LOCK_TASK_AUTH_PINNABLE);
+        Task dialer = getTask("com.example.dialer", Task.LOCK_TASK_AUTH_PINNABLE);
         when(mTelecomManager.getSystemDialerPackage())
                 .thenReturn(dialer.intent.getComponent().getPackageName());
 
@@ -291,7 +291,7 @@
     @Test
     public void testStopLockTaskMode() throws Exception {
         // GIVEN one task record with whitelisted auth that is in lock task mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN the same caller calls stopLockTaskMode
@@ -308,7 +308,7 @@
     @Test(expected = SecurityException.class)
     public void testStopLockTaskMode_differentCaller() {
         // GIVEN one task record with whitelisted auth that is in lock task mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN a different caller calls stopLockTaskMode
@@ -320,7 +320,7 @@
     @Test
     public void testStopLockTaskMode_systemCaller() {
         // GIVEN one task record with whitelisted auth that is in lock task mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // WHEN system calls stopLockTaskMode
@@ -333,8 +333,8 @@
     @Test
     public void testStopLockTaskMode_twoTasks() throws Exception {
         // GIVEN two task records with whitelisted auth that is in lock task mode
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
-        TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -354,8 +354,8 @@
     @Test
     public void testStopLockTaskMode_rootTask() throws Exception {
         // GIVEN two task records with whitelisted auth that is in lock task mode
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
-        TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -375,7 +375,7 @@
     @Test
     public void testStopLockTaskMode_pinned() throws Exception {
         // GIVEN one task records that is in pinned mode
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_PINNABLE);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_PINNABLE);
         mLockTaskController.startLockTaskMode(tr, true, SYSTEM_UID);
         // GIVEN that the keyguard is required to show after unlocking
         Settings.Secure.putInt(mContext.getContentResolver(),
@@ -402,8 +402,8 @@
     @Test
     public void testClearLockedTasks() throws Exception {
         // GIVEN two task records with whitelisted auth that is in lock task mode
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
-        TaskRecord tr2 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr2 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, false, TEST_UID);
         mLockTaskController.startLockTaskMode(tr2, false, TEST_UID);
 
@@ -430,7 +430,7 @@
                 .thenReturn(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
 
         // AND there is a task record
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -450,7 +450,7 @@
                 .thenReturn(true);
 
         // AND there is a task record
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -467,7 +467,7 @@
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 1, mContext.getUserId());
 
         // AND there is a task record
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -484,7 +484,7 @@
                 Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, 0, mContext.getUserId());
 
         // AND there is a task record
-        TaskRecord tr1 = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr1 = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr1, true, TEST_UID);
 
         // WHEN calling clearLockedTasks on the root task
@@ -531,8 +531,8 @@
     @Test
     public void testUpdateLockTaskPackages_taskRemoved() throws Exception {
         // GIVEN two tasks which are whitelisted initially
-        TaskRecord tr1 = getTaskRecordForUpdate(TEST_PACKAGE_NAME, true);
-        TaskRecord tr2 = getTaskRecordForUpdate(TEST_PACKAGE_NAME_2, false);
+        Task tr1 = getTaskForUpdate(TEST_PACKAGE_NAME, true);
+        Task tr2 = getTaskForUpdate(TEST_PACKAGE_NAME_2, false);
         String[] whitelist = {TEST_PACKAGE_NAME, TEST_PACKAGE_NAME_2};
         mLockTaskController.updateLockTaskPackages(TEST_USER_ID, whitelist);
 
@@ -570,7 +570,7 @@
     @Test
     public void testUpdateLockTaskFeatures() throws Exception {
         // GIVEN a locked task
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN lock task mode should be started with default status bar masks
@@ -612,7 +612,7 @@
     @Test
     public void testUpdateLockTaskFeatures_differentUser() throws Exception {
         // GIVEN a locked task
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN lock task mode should be started with default status bar masks
@@ -634,7 +634,7 @@
     @Test
     public void testUpdateLockTaskFeatures_keyguard() {
         // GIVEN a locked task
-        TaskRecord tr = getTaskRecord(TaskRecord.LOCK_TASK_AUTH_WHITELISTED);
+        Task tr = getTask(Task.LOCK_TASK_AUTH_WHITELISTED);
         mLockTaskController.startLockTaskMode(tr, false, TEST_UID);
 
         // THEN keyguard should be disabled
@@ -693,18 +693,18 @@
         assertTrue((StatusBarManager.DISABLE2_QUICK_SETTINGS & flags.second) != 0);
     }
 
-    private TaskRecord getTaskRecord(int lockTaskAuth) {
-        return getTaskRecord(TEST_PACKAGE_NAME, lockTaskAuth);
+    private Task getTask(int lockTaskAuth) {
+        return getTask(TEST_PACKAGE_NAME, lockTaskAuth);
     }
 
-    private TaskRecord getTaskRecord(String pkg, int lockTaskAuth) {
+    private Task getTask(String pkg, int lockTaskAuth) {
         final Intent intent = new Intent()
                 .setComponent(ComponentName.createRelative(pkg, TEST_CLASS_NAME));
-        return getTaskRecord(intent, lockTaskAuth);
+        return getTask(intent, lockTaskAuth);
     }
 
-    private TaskRecord getTaskRecord(Intent intent, int lockTaskAuth) {
-        TaskRecord tr = mock(TaskRecord.class);
+    private Task getTask(Intent intent, int lockTaskAuth) {
+        Task tr = mock(Task.class);
         tr.mLockTaskAuth = lockTaskAuth;
         tr.intent = intent;
         tr.mUserId = TEST_USER_ID;
@@ -714,17 +714,15 @@
     /**
      * @param isAppAware {@code true} if the app has marked if_whitelisted in its manifest
      */
-    private TaskRecord getTaskRecordForUpdate(String pkg, boolean isAppAware) {
+    private Task getTaskForUpdate(String pkg, boolean isAppAware) {
         final int authIfWhitelisted = isAppAware
-                ? TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE
-                : TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-        TaskRecord tr = getTaskRecord(pkg, authIfWhitelisted);
+                ? Task.LOCK_TASK_AUTH_LAUNCHABLE
+                : Task.LOCK_TASK_AUTH_WHITELISTED;
+        Task tr = getTask(pkg, authIfWhitelisted);
         doAnswer((invocation) -> {
             boolean isWhitelisted =
                     mLockTaskController.isPackageWhitelisted(TEST_USER_ID, pkg);
-            tr.mLockTaskAuth = isWhitelisted
-                    ? authIfWhitelisted
-                    : TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+            tr.mLockTaskAuth = isWhitelisted ? authIfWhitelisted : Task.LOCK_TASK_AUTH_PINNABLE;
             return null;
         }).when(tr).setLockTaskAuth();
         return tr;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 69091c6..e0ffb0d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -101,8 +101,8 @@
     private TestRecentTasks mRecentTasks;
     private TestRunningTasks mRunningTasks;
 
-    private ArrayList<TaskRecord> mTasks;
-    private ArrayList<TaskRecord> mSameDocumentTasks;
+    private ArrayList<Task> mTasks;
+    private ArrayList<Task> mSameDocumentTasks;
 
     private CallbacksRecorder mCallbacksRecorder;
 
@@ -172,8 +172,8 @@
     public void testAddTasksNoMultiple_expectNoTrim() {
         // Add same non-multiple-task document tasks will remove the task (to re-add it) but not
         // trim it
-        TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
-        TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
+        Task documentTask1 = createDocumentTask(".DocumentTask1");
+        Task documentTask2 = createDocumentTask(".DocumentTask1");
         mRecentTasks.add(documentTask1);
         mRecentTasks.add(documentTask2);
         assertThat(mCallbacksRecorder.mAdded).contains(documentTask1);
@@ -186,8 +186,8 @@
     public void testAddTasksMaxTaskRecents_expectNoTrim() {
         // Add a task hitting max-recents for that app will remove the task (to add the next one)
         // but not trim it
-        TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
-        TaskRecord documentTask2 = createDocumentTask(".DocumentTask1");
+        Task documentTask1 = createDocumentTask(".DocumentTask1");
+        Task documentTask2 = createDocumentTask(".DocumentTask1");
         documentTask1.maxRecents = 1;
         documentTask2.maxRecents = 1;
         mRecentTasks.add(documentTask1);
@@ -202,7 +202,7 @@
     public void testAddTasksSameTask_expectNoTrim() {
         // Add a task that is already in the task list does not trigger any callbacks, it just
         // moves in the list
-        TaskRecord documentTask1 = createDocumentTask(".DocumentTask1");
+        Task documentTask1 = createDocumentTask(".DocumentTask1");
         mRecentTasks.add(documentTask1);
         mRecentTasks.add(documentTask1);
         assertThat(mCallbacksRecorder.mAdded).hasSize(1);
@@ -214,9 +214,9 @@
     @Test
     public void testAddTasksMultipleDocumentTasks_expectNoTrim() {
         // Add same multiple-task document tasks does not trim the first tasks
-        TaskRecord documentTask1 = createDocumentTask(".DocumentTask1",
+        Task documentTask1 = createDocumentTask(".DocumentTask1",
                 FLAG_ACTIVITY_MULTIPLE_TASK);
-        TaskRecord documentTask2 = createDocumentTask(".DocumentTask1",
+        Task documentTask2 = createDocumentTask(".DocumentTask1",
                 FLAG_ACTIVITY_MULTIPLE_TASK);
         mRecentTasks.add(documentTask1);
         mRecentTasks.add(documentTask2);
@@ -231,10 +231,10 @@
     public void testAddTasksMultipleTasks_expectRemovedNoTrim() {
         // Add multiple same-affinity non-document tasks, ensure that it removes the other task,
         // but that it does not trim it
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .build();
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .build();
         mRecentTasks.add(task1);
@@ -255,10 +255,10 @@
     public void testAddTasksDifferentStacks_expectNoRemove() {
         // Adding the same task with different activity types should not trigger removal of the
         // other task
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .setStack(mDisplay.getHomeStack()).build();
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
                 .setStack(mStack).build();
         mRecentTasks.add(task1);
@@ -274,7 +274,7 @@
     public void testAddTaskCompatibleActivityType_expectRemove() {
         // Test with undefined activity type since the type is not persisted by the task persister
         // and we want to ensure that a new task will match a restored task
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -283,7 +283,7 @@
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -298,7 +298,7 @@
 
     @Test
     public void testAddTaskCompatibleActivityTypeDifferentUser_expectNoRemove() {
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .setUserId(TEST_USER_0_ID)
@@ -308,7 +308,7 @@
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .setUserId(TEST_USER_1_ID)
@@ -323,7 +323,7 @@
 
     @Test
     public void testAddTaskCompatibleWindowingMode_expectRemove() {
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -332,7 +332,7 @@
         mRecentTasks.add(task1);
         mCallbacksRecorder.clear();
 
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -349,7 +349,7 @@
 
     @Test
     public void testAddTaskIncompatibleWindowingMode_expectNoRemove() {
-        TaskRecord task1 = createTaskBuilder(".Task1")
+        Task task1 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -357,7 +357,7 @@
         assertEquals(WINDOWING_MODE_FULLSCREEN, task1.getWindowingMode());
         mRecentTasks.add(task1);
 
-        TaskRecord task2 = createTaskBuilder(".Task1")
+        Task task2 = createTaskBuilder(".Task1")
                 .setFlags(FLAG_ACTIVITY_NEW_TASK)
                 .setStack(mStack)
                 .build();
@@ -421,13 +421,13 @@
     @Test
     public void testOrderedIteration() {
         mRecentTasks.setOnlyTestVisibleRange();
-        TaskRecord task1 = createTaskBuilder(".Task1").build();
+        Task task1 = createTaskBuilder(".Task1").build();
         task1.lastActiveTime = new Random().nextInt();
-        TaskRecord task2 = createTaskBuilder(".Task1").build();
+        Task task2 = createTaskBuilder(".Task1").build();
         task2.lastActiveTime = new Random().nextInt();
-        TaskRecord task3 = createTaskBuilder(".Task1").build();
+        Task task3 = createTaskBuilder(".Task1").build();
         task3.lastActiveTime = new Random().nextInt();
-        TaskRecord task4 = createTaskBuilder(".Task1").build();
+        Task task4 = createTaskBuilder(".Task1").build();
         task4.lastActiveTime = new Random().nextInt();
         mRecentTasks.add(task1);
         mRecentTasks.add(task2);
@@ -435,9 +435,9 @@
         mRecentTasks.add(task4);
 
         long prevLastActiveTime = 0;
-        final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+        final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
         for (int i = 0; i < tasks.size(); i++) {
-            final TaskRecord task = tasks.get(i);
+            final Task task = tasks.get(i);
             assertThat(prevLastActiveTime).isLessThan(task.lastActiveTime);
             prevLastActiveTime = task.lastActiveTime;
         }
@@ -462,8 +462,8 @@
     @Test
     public void testTrimQuietProfileTasks() {
         mRecentTasks.setOnlyTestVisibleRange();
-        TaskRecord qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
-        TaskRecord qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
+        Task qt1 = createTaskBuilder(".QuietTask1").setUserId(TEST_QUIET_USER_ID).build();
+        Task qt2 = createTaskBuilder(".QuietTask2").setUserId(TEST_QUIET_USER_ID).build();
         mRecentTasks.add(qt1);
         mRecentTasks.add(qt2);
 
@@ -479,14 +479,14 @@
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(-1 /* min */, -1 /* max */, 50 /* ms */);
 
-        TaskRecord t1 = createTaskBuilder(".Task1").build();
+        Task t1 = createTaskBuilder(".Task1").build();
         t1.touchActiveTime();
         mRecentTasks.add(t1);
 
         // Force a small sleep just beyond the session duration
         SystemClock.sleep(75);
 
-        TaskRecord t2 = createTaskBuilder(".Task2").build();
+        Task t2 = createTaskBuilder(".Task2").build();
         t2.touchActiveTime();
         mRecentTasks.add(t2);
 
@@ -499,10 +499,10 @@
         mRecentTasks.setOnlyTestVisibleRange();
         mRecentTasks.setParameters(-1 /* min */, 4 /* max */, -1 /* ms */);
 
-        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+        Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                 .build();
-        TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+        Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                 .build();
 
@@ -519,12 +519,12 @@
     @Test
     public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
         // Create some set of tasks, some of which are visible and some are not
-        TaskRecord homeTask = setTaskActivityType(
+        Task homeTask = setTaskActivityType(
                 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
                 ACTIVITY_TYPE_HOME);
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
-        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+        Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                 .build();
         excludedTask1.mUserSetupComplete = true;
@@ -537,25 +537,25 @@
     @Test
     public void testVisibleTasks_excludedFromRecents_withExcluded() {
         // Create some set of tasks, some of which are visible and some are not
-        TaskRecord t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
+        Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
         t1.mUserSetupComplete = true;
         mRecentTasks.add(t1);
-        TaskRecord homeTask = setTaskActivityType(
+        Task homeTask = setTaskActivityType(
                 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
                 ACTIVITY_TYPE_HOME);
         homeTask.mUserSetupComplete = true;
         mRecentTasks.add(homeTask);
-        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+        Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                 .build();
         excludedTask1.mUserSetupComplete = true;
         mRecentTasks.add(excludedTask1);
-        TaskRecord excludedTask2 = createTaskBuilder(".ExcludedTask2")
+        Task excludedTask2 = createTaskBuilder(".ExcludedTask2")
                 .setFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                 .build();
         excludedTask2.mUserSetupComplete = true;
         mRecentTasks.add(excludedTask2);
-        TaskRecord t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
+        Task t2 = createTaskBuilder("com.android.pkg2", ".Task1").build();
         t2.mUserSetupComplete = true;
         mRecentTasks.add(t2);
 
@@ -568,7 +568,7 @@
         mRecentTasks.setParameters(5 /* min */, -1 /* max */, 25 /* ms */);
 
         for (int i = 0; i < 4; i++) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             task.touchActiveTime();
             mRecentTasks.add(task);
         }
@@ -589,7 +589,7 @@
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */);
 
         for (int i = 0; i < 5; i++) {
-            final TaskRecord task = mTasks.get(i);
+            final Task task = mTasks.get(i);
             task.touchActiveTime();
             mRecentTasks.add(task);
         }
@@ -612,7 +612,7 @@
         ActivityStack singleTaskStack = singleTaskDisplay.createStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
 
-        TaskRecord excludedTask1 = createTaskBuilder(".ExcludedTask1")
+        Task excludedTask1 = createTaskBuilder(".ExcludedTask1")
                 .setStack(singleTaskStack)
                 .build();
 
@@ -771,7 +771,7 @@
 
         // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
         // the home stack is trimmed once a new task is added
-        final TaskRecord behindHomeTask = createTaskBuilder(".Task1")
+        final Task behindHomeTask = createTaskBuilder(".Task1")
                 .setStack(behindHomeStack)
                 .build();
         mRecentTasks.add(behindHomeTask);
@@ -809,7 +809,7 @@
         mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".Task4").build());
         mRecentTasks.removeTasksByPackageName("com.android.pkg1", TEST_USER_0_ID);
 
-        final ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+        final ArrayList<Task> tasks = mRecentTasks.getRawTasks();
         for (int i = 0; i < tasks.size(); i++) {
             if (tasks.get(i).intent.getComponent().getPackageName().equals("com.android.pkg1")) {
                 fail("Expected com.android.pkg1 tasks to be removed");
@@ -822,30 +822,30 @@
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
 
         // Create some set of tasks, some of which are visible and some are not
-        TaskRecord t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
+        Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
         mRecentTasks.add(t1);
         mRecentTasks.add(setTaskActivityType(
                 createTaskBuilder("com.android.pkg1", ".HomeTask").build(),
                 ACTIVITY_TYPE_HOME));
-        TaskRecord t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
+        Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
         mRecentTasks.add(t2);
         mRecentTasks.add(setTaskWindowingMode(
                 createTaskBuilder("com.android.pkg1", ".PipTask").build(),
                 WINDOWING_MODE_PINNED));
-        TaskRecord t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
+        Task t3 = createTaskBuilder("com.android.pkg3", ".Task3").build();
         mRecentTasks.add(t3);
 
         // Create some more tasks that are out of visible range, but are still visible
-        TaskRecord t4 = createTaskBuilder("com.android.pkg3", ".Task4").build();
+        Task t4 = createTaskBuilder("com.android.pkg3", ".Task4").build();
         mRecentTasks.add(t4);
-        TaskRecord t5 = createTaskBuilder("com.android.pkg3", ".Task5").build();
+        Task t5 = createTaskBuilder("com.android.pkg3", ".Task5").build();
         mRecentTasks.add(t5);
 
         // Create some more tasks that are out of the active session range, but are still visible
-        TaskRecord t6 = createTaskBuilder("com.android.pkg3", ".Task6").build();
+        Task t6 = createTaskBuilder("com.android.pkg3", ".Task6").build();
         t6.lastActiveTime = SystemClock.elapsedRealtime() - 200;
         mRecentTasks.add(t6);
-        TaskRecord t7 = createTaskBuilder("com.android.pkg3", ".Task7").build();
+        Task t7 = createTaskBuilder("com.android.pkg3", ".Task7").build();
         t7.lastActiveTime = SystemClock.elapsedRealtime() - 200;
         mRecentTasks.add(t7);
 
@@ -859,17 +859,17 @@
         mRecentTasks.setParameters(-1 /* min */, 3 /* max */, 100 /* ms */);
 
         // Create a visible task per user
-        TaskRecord t1 = createTaskBuilder(".Task1")
+        Task t1 = createTaskBuilder(".Task1")
                 .setUserId(TEST_USER_0_ID)
                 .build();
         mRecentTasks.add(t1);
 
-        TaskRecord t2 = createTaskBuilder(".Task2")
+        Task t2 = createTaskBuilder(".Task2")
                 .setUserId(TEST_QUIET_USER_ID)
                 .build();
         mRecentTasks.add(t2);
 
-        TaskRecord t3 = createTaskBuilder(".Task3")
+        Task t3 = createTaskBuilder(".Task3")
                 .setUserId(TEST_USER_1_ID)
                 .build();
         mRecentTasks.add(t3);
@@ -881,12 +881,12 @@
 
     @Test
     public void testNotRestoreRecentTaskApis() {
-        final TaskRecord task = createTaskBuilder(".Task").build();
+        final Task task = createTaskBuilder(".Task").build();
         final int taskId = task.mTaskId;
         mRecentTasks.add(task);
         // Only keep the task in RecentTasks.
         task.removeIfPossible();
-        mStack.remove();
+        mStack.removeIfPossible();
 
         // The following APIs should not restore task from recents to the active list.
         assertNotRestoreTask(() -> mService.setFocusedTask(taskId));
@@ -906,7 +906,7 @@
 
     @Test
     public void addTask_callsTaskNotificationController() {
-        final TaskRecord task = createTaskBuilder(".Task").build();
+        final Task task = createTaskBuilder(".Task").build();
 
         mRecentTasks.add(task);
         mRecentTasks.remove(task);
@@ -918,7 +918,7 @@
 
     @Test
     public void removeTask_callsTaskNotificationController() {
-        final TaskRecord task = createTaskBuilder(".Task").build();
+        final Task task = createTaskBuilder(".Task").build();
 
         mRecentTasks.add(task);
         mRecentTasks.remove(task);
@@ -931,8 +931,8 @@
 
     @Test
     public void removeALlVisibleTask_callsTaskNotificationController_twice() {
-        final TaskRecord task1 = createTaskBuilder(".Task").build();
-        final TaskRecord task2 = createTaskBuilder(".Task2").build();
+        final Task task1 = createTaskBuilder(".Task").build();
+        final Task task2 = createTaskBuilder(".Task2").build();
 
         mRecentTasks.add(task1);
         mRecentTasks.add(task2);
@@ -948,8 +948,8 @@
      * Ensures that the raw recent tasks list is in the provided order. Note that the expected tasks
      * should be ordered from least to most recent.
      */
-    private void assertRecentTasksOrder(TaskRecord... expectedTasks) {
-        ArrayList<TaskRecord> tasks = mRecentTasks.getRawTasks();
+    private void assertRecentTasksOrder(Task... expectedTasks) {
+        ArrayList<Task> tasks = mRecentTasks.getRawTasks();
         assertTrue(expectedTasks.length == tasks.size());
         for (int i = 0; i < tasks.size(); i++)  {
             assertTrue(expectedTasks[i] == tasks.get(i));
@@ -960,7 +960,7 @@
      * Ensures that the recent tasks list is in the provided order. Note that the expected tasks
      * should be ordered from least to most recent.
      */
-    private void assertGetRecentTasksOrder(int getRecentTaskFlags, TaskRecord... expectedTasks) {
+    private void assertGetRecentTasksOrder(int getRecentTaskFlags, Task... expectedTasks) {
         doNothing().when(mRecentTasks).loadUserRecentsLocked(anyInt());
         doReturn(true).when(mRecentTasks).isUserRunning(anyInt(), anyInt());
         List<RecentTaskInfo> infos = mRecentTasks.getRecentTasks(MAX_VALUE, getRecentTaskFlags,
@@ -1079,12 +1079,12 @@
                 .setUserId(TEST_USER_0_ID);
     }
 
-    private TaskRecord createDocumentTask(String className) {
+    private Task createDocumentTask(String className) {
         return createDocumentTask(className, 0);
     }
 
-    private TaskRecord createDocumentTask(String className, int flags) {
-        TaskRecord task = createTaskBuilder(className)
+    private Task createDocumentTask(String className, int flags) {
+        Task task = createTaskBuilder(className)
                 .setFlags(FLAG_ACTIVITY_NEW_DOCUMENT | flags)
                 .build();
         task.affinity = null;
@@ -1092,7 +1092,7 @@
         return task;
     }
 
-    private TaskRecord setTaskActivityType(TaskRecord task,
+    private Task setTaskActivityType(Task task,
             @WindowConfiguration.ActivityType int activityType) {
         Configuration config1 = new Configuration();
         config1.windowConfiguration.setActivityType(activityType);
@@ -1100,7 +1100,7 @@
         return task;
     }
 
-    private TaskRecord setTaskWindowingMode(TaskRecord task,
+    private Task setTaskWindowingMode(Task task,
             @WindowConfiguration.WindowingMode int windowingMode) {
         Configuration config1 = new Configuration();
         config1.windowConfiguration.setWindowingMode(windowingMode);
@@ -1112,14 +1112,14 @@
         assertTrimmed();
     }
 
-    private void assertTrimmed(TaskRecord... tasks) {
-        final ArrayList<TaskRecord> trimmed = mCallbacksRecorder.mTrimmed;
-        final ArrayList<TaskRecord> removed = mCallbacksRecorder.mRemoved;
+    private void assertTrimmed(Task... tasks) {
+        final ArrayList<Task> trimmed = mCallbacksRecorder.mTrimmed;
+        final ArrayList<Task> removed = mCallbacksRecorder.mRemoved;
         assertWithMessage("Expected " + tasks.length + " trimmed tasks, got " + trimmed.size())
                 .that(trimmed).hasSize(tasks.length);
         assertWithMessage("Expected " + tasks.length + " removed tasks, got " + removed.size())
                 .that(removed).hasSize(tasks.length);
-        for (TaskRecord task : tasks) {
+        for (Task task : tasks) {
             assertWithMessage("Expected trimmed task: " + task).that(trimmed).contains(task);
             assertWithMessage("Expected removed task: " + task).that(removed).contains(task);
         }
@@ -1141,9 +1141,9 @@
     }
 
     private static class CallbacksRecorder implements Callbacks {
-        public final ArrayList<TaskRecord> mAdded = new ArrayList<>();
-        public final ArrayList<TaskRecord> mTrimmed = new ArrayList<>();
-        public final ArrayList<TaskRecord> mRemoved = new ArrayList<>();
+        public final ArrayList<Task> mAdded = new ArrayList<>();
+        public final ArrayList<Task> mTrimmed = new ArrayList<>();
+        public final ArrayList<Task> mRemoved = new ArrayList<>();
 
         void clear() {
             mAdded.clear();
@@ -1152,12 +1152,12 @@
         }
 
         @Override
-        public void onRecentTaskAdded(TaskRecord task) {
+        public void onRecentTaskAdded(Task task) {
             mAdded.add(task);
         }
 
         @Override
-        public void onRecentTaskRemoved(TaskRecord task, boolean wasTrimmed, boolean killProcess) {
+        public void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {
             if (wasTrimmed) {
                 mTrimmed.add(task);
             }
@@ -1167,7 +1167,7 @@
 
     private static class TestTaskPersister extends TaskPersister {
         public SparseBooleanArray mUserTaskIdsOverride;
-        public ArrayList<TaskRecord> mUserTasksOverride;
+        public ArrayList<Task> mUserTasksOverride;
 
         TestTaskPersister(File workingDir) {
             super(workingDir);
@@ -1182,7 +1182,7 @@
         }
 
         @Override
-        List<TaskRecord> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
+        List<Task> restoreTasksForUserLocked(int userId, SparseBooleanArray preaddedTasks) {
             if (mUserTasksOverride != null) {
                 return mUserTasksOverride;
             }
@@ -1270,7 +1270,7 @@
         }
 
         @Override
-        protected boolean isTrimmable(TaskRecord task) {
+        protected boolean isTrimmable(Task task) {
             return mIsTrimmableOverride || super.isTrimmable(task);
         }
     }
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 ca8f535..41cbd81 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -234,7 +234,7 @@
 
         // Start the recents animation.
         RecentsAnimationCallbacks recentsAnimation = startRecentsActivity(
-                targetActivity.getTaskRecord().getBaseIntent().getComponent(),
+                targetActivity.getTask().getBaseIntent().getComponent(),
                 true /* getRecentsAnimation */);
         // Ensure launch-behind is set for being visible.
         assertTrue(targetActivity.mLaunchTaskBehind);
@@ -325,7 +325,7 @@
         // Start the recents animation
         startRecentsActivity();
 
-        fullscreenStack.remove();
+        fullscreenStack.removeIfPossible();
 
         // Ensure that the recents animation was NOT canceled
         verify(mService.mWindowManager, times(0)).cancelRecentsAnimation(
@@ -342,7 +342,7 @@
                 .setCreateTask(true)
                 .setComponent(new ComponentName(mContext.getPackageName(), "Home2"))
                 .build();
-        otherUserHomeActivity.getTaskRecord().mUserId = TEST_USER_ID;
+        otherUserHomeActivity.getTask().mUserId = TEST_USER_ID;
 
         ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
@@ -357,7 +357,7 @@
                 any() /* starting */, anyInt() /* configChanges */,
                 anyBoolean() /* preserveWindows */);
 
-        startRecentsActivity(otherUserHomeActivity.getTaskRecord().getBaseIntent().getComponent(),
+        startRecentsActivity(otherUserHomeActivity.getTask().getBaseIntent().getComponent(),
                 true);
 
         // Ensure we find the task for the right user and it is made visible
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index e0e9a58..3cc781c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -101,7 +101,7 @@
     @Test
     public void testRestoringInvalidTask() {
         mRootActivityContainer.getDefaultDisplay().removeAllTasks();
-        TaskRecord task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
+        Task task = mRootActivityContainer.anyTaskForId(0 /*taskId*/,
                 MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
         assertNull(task);
     }
@@ -114,7 +114,7 @@
     public void testReplacingTaskInPinnedStack() {
         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
                 .setStack(mFullscreenStack).build();
-        final TaskRecord task = firstActivity.getTaskRecord();
+        final Task task = firstActivity.getTask();
 
         final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(task)
                 .setStack(mFullscreenStack).build();
@@ -148,7 +148,7 @@
     }
 
     private static void ensureStackPlacement(ActivityStack stack, ActivityRecord... activities) {
-        final TaskRecord task = stack.getAllTasks().get(0);
+        final Task task = stack.getAllTasks().get(0);
         final ArrayList<ActivityRecord> stackActivities = new ArrayList<>();
 
         for (int i = 0; i < task.getChildCount(); i++) {
@@ -171,8 +171,11 @@
     public void testApplySleepTokens() {
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         final KeyguardController keyguard = mSupervisor.getKeyguardController();
-        final ActivityStack stack = mock(ActivityStack.class);
-        display.addChild(stack, 0 /* position */);
+        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                .setCreateActivity(false)
+                .setDisplay(display)
+                .setOnTop(false)
+                .build();
 
         // Make sure we wake and resume in the case the display is turning on and the keyguard is
         // not showing.
@@ -276,7 +279,7 @@
         assertTrue(pinnedActivity.isFocusable());
 
         // Without the overridding activity, stack should not be focusable.
-        pinnedStack.removeChild(pinnedActivity.getTaskRecord(), "testFocusability");
+        pinnedStack.removeChild(pinnedActivity.getTask(), "testFocusability");
         assertFalse(pinnedStack.isFocusable());
     }
 
@@ -291,7 +294,7 @@
         final ActivityStack primaryStack = mRootActivityContainer.getDefaultDisplay()
                 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
                         true /* onTop */);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
         final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
 
         // Find a launch stack for the top activity in split-screen primary, while requesting
@@ -320,7 +323,7 @@
                 .setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)
                 .setOnTop(true)
                 .build();
-        final TaskRecord task = primaryStack.topTask();
+        final Task task = primaryStack.topTask();
 
         // Resize dock stack.
         mService.resizeDockedStack(stackSize, taskSize, null, null, null);
@@ -340,7 +343,7 @@
         final ActivityStack targetStack = new StackBuilder(mRootActivityContainer)
                 .setOnTop(false)
                 .build();
-        final TaskRecord targetTask = targetStack.getChildAt(0);
+        final Task targetTask = targetStack.getChildAt(0);
 
         // Create Recents on top of the display.
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).setActivityType(
@@ -363,14 +366,14 @@
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */);
-        final TaskRecord targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+        final Task targetTask = new TaskBuilder(mSupervisor).setStack(targetStack).build();
 
         // Create Recents on secondary display.
         final TestActivityDisplay secondDisplay = addNewActivityDisplayAt(
                 ActivityDisplay.POSITION_TOP);
         final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_RECENTS, true /* onTop */);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
         new ActivityBuilder(mService).setTask(task).build();
 
         final String reason = "findTaskToMoveToFront";
@@ -390,7 +393,7 @@
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
         final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
         display.positionChildAtBottom(targetStack);
 
@@ -414,8 +417,8 @@
      */
     @Test
     public void testResumeFocusedStacksStartsHomeActivity_NoActivities() {
-        mFullscreenStack.remove();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().remove();
+        mFullscreenStack.removeIfPossible();
+        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
         mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
 
@@ -436,8 +439,8 @@
      */
     @Test
     public void testResumeFocusedStacksStartsHomeActivity_ActivityOnSecondaryScreen() {
-        mFullscreenStack.remove();
-        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().remove();
+        mFullscreenStack.removeIfPossible();
+        mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY).getHomeStack().removeIfPossible();
         mService.mRootActivityContainer.getActivityDisplay(DEFAULT_DISPLAY)
                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP);
 
@@ -446,7 +449,7 @@
                 ActivityDisplay.POSITION_TOP);
         final ActivityStack stack = secondDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
         new ActivityBuilder(mService).setTask(task).build();
 
         doReturn(true).when(mRootActivityContainer).resumeHomeActivity(any(), any(), anyInt());
@@ -470,7 +473,7 @@
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
         final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
         activity.setState(ActivityState.RESUMED, "test");
 
@@ -490,7 +493,7 @@
         final ActivityDisplay display = mRootActivityContainer.getDefaultDisplay();
         final ActivityStack targetStack = spy(display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* onTop */));
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(targetStack).build();
         final ActivityRecord activity = new ActivityBuilder(mService).setTask(task).build();
         activity.setState(ActivityState.RESUMED, "test");
         display.positionChildAtBottom(targetStack);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index 8326ad8..15dcbf5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -20,8 +20,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
-
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
@@ -66,9 +64,10 @@
 
         final int numStacks = 2;
         for (int stackIndex = 0; stackIndex < numStacks; stackIndex++) {
-            final ActivityStack stack =
-                    new StackBuilder(mRootActivityContainer).setCreateActivity(false).build();
-            display.addChild(stack, POSITION_BOTTOM);
+            final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+                    .setCreateActivity(false)
+                    .setOnTop(false)
+                    .build();
         }
 
         final int numTasks = 10;
@@ -104,9 +103,9 @@
     /**
      * Create a task with a single activity in it, with the given last active time.
      */
-    private TaskRecord createTask(ActivityStack stack, String className, int taskId,
+    private Task createTask(ActivityStack stack, String className, int taskId,
             int lastActiveTime) {
-        final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
+        final Task task = new TaskBuilder(mService.mStackSupervisor)
                 .setComponent(new ComponentName(mContext.getPackageName(), className))
                 .setTaskId(taskId)
                 .setStack(stack)
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index ad1d1af..562775c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -293,7 +293,6 @@
         final ActivityStack homeStack = display.getStack(
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME);
         spyOn(homeStack);
-        spyOn(homeStack.mTaskStack);
     }
 
     private void tearDown() {
@@ -311,6 +310,7 @@
         DisplayThread.dispose();
         AnimationThread.dispose();
         UiThread.dispose();
+        SurfaceAnimationThread.dispose();
         mInputChannel.dispose();
 
         tearDownLocalServices();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 5a141ae..27ebd5a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -95,7 +95,7 @@
 
     @Test
     public void testReturnsSkipWithEmptyActivity() {
-        final TaskRecord task = new TaskBuilder(mSupervisor).build();
+        final Task task = new TaskBuilder(mSupervisor).build();
         assertEquals(RESULT_SKIP, mTarget.onCalculate(task, /* layout */ null,
                 /* activity */ null, /* source */ null, /* options */ null, mCurrent, mResult));
     }
@@ -183,7 +183,7 @@
         ActivityRecord reusableActivity = createSourceActivity(fullscreenDisplay);
         ActivityRecord source = createSourceActivity(freeformDisplay);
 
-        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTask(),
                 /* layout */ null, mActivity, source, /* options */ null, mCurrent, mResult));
 
         assertEquals(fullscreenDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -195,7 +195,7 @@
                 WINDOWING_MODE_FREEFORM);
         ActivityRecord source = createSourceActivity(freeformDisplay);
 
-        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(source.getTaskRecord(), null /* layout */,
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(source.getTask(), null /* layout */,
                 null /* activity */, null /* source */, null /* options */, mCurrent, mResult));
 
         assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -214,7 +214,7 @@
         source.mHandoverLaunchDisplayId = freeformDisplay.mDisplayId;
         source.noDisplay = true;
 
-        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTaskRecord(),
+        assertEquals(RESULT_CONTINUE, mTarget.onCalculate(reusableActivity.getTask(),
                 null /* layout */, mActivity, source, null /* options */, mCurrent, mResult));
 
         assertEquals(freeformDisplay.mDisplayId, mResult.mPreferredDisplayId);
@@ -1319,7 +1319,7 @@
         final ActivityStack stack = display.createStack(display.getWindowingMode(),
                 ACTIVITY_TYPE_STANDARD, true);
         stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
-        final TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        final Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
         // Just work around the unnecessary adjustments for bounds.
         task.getWindowConfiguration().setBounds(bounds);
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index d2342f0..8e32dad 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -66,8 +66,7 @@
                 any(InputChannel.class))).thenReturn(true);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        // TODO(task-merge): Remove cast.
-        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_RESIZEABLE);
+        mWindow.getTask().setResizeMode(RESIZE_MODE_RESIZEABLE);
         mWindow.mInputChannel = new InputChannel();
         mWm.mWindowMap.put(mWindow.mClient.asBinder(), mWindow);
         doReturn(mock(InputMonitor.class)).when(mDisplayContent).getInputMonitor();
@@ -143,8 +142,7 @@
         doReturn(mWindow.getTask()).when(content).findTaskForResizePoint(anyInt(), anyInt());
         assertNotNull(mWindow.getTask().getTopVisibleAppMainWindow());
 
-        // TODO(task-merge): Remove cast.
-        ((TaskRecord) mWindow.getTask()).setResizeMode(RESIZE_MODE_UNRESIZEABLE);
+        mWindow.getTask().setResizeMode(RESIZE_MODE_UNRESIZEABLE);
 
         mTarget.handleTapOutsideTask(content, 0, 0);
         // Wait until the looper processes finishTaskPositioning.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 2cafc96..faa9f11 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -72,13 +72,12 @@
 import androidx.test.filters.MediumTest;
 
 import com.android.internal.app.IVoiceInteractor;
-import com.android.server.wm.TaskRecord.TaskRecordFactory;
+import com.android.server.wm.Task.TaskFactory;
 import com.android.server.wm.utils.WmDisplayCutout;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mockito;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -88,10 +87,9 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
-import java.util.ArrayList;
 
 /**
- * Tests for exercising {@link TaskRecord}.
+ * Tests for exercising {@link Task}.
  *
  * Build/Install/Run:
  *  atest WmTests:TaskRecordTests
@@ -107,31 +105,31 @@
 
     @Before
     public void setUp() throws Exception {
-        TaskRecord.setTaskRecordFactory(null);
+        Task.setTaskFactory(null);
         mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
         removeGlobalMinSizeRestriction();
     }
 
     @Test
     public void testRestoreWindowedTask() throws Exception {
-        final TaskRecord expected = createTaskRecord(64);
+        final Task expected = createTask(64);
         expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
 
         final byte[] serializedBytes = serializeToBytes(expected);
-        final TaskRecord actual = restoreFromBytes(serializedBytes);
+        final Task actual = restoreFromBytes(serializedBytes);
         assertEquals(expected.mTaskId, actual.mTaskId);
         assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
     }
 
     @Test
     public void testDefaultTaskFactoryNotNull() throws Exception {
-        assertNotNull(TaskRecord.getTaskRecordFactory());
+        assertNotNull(Task.getTaskFactory());
     }
 
     /** Ensure we have no chance to modify the original intent. */
     @Test
     public void testCopyBaseIntentForTaskInfo() {
-        final TaskRecord task = createTaskRecord(1);
+        final Task task = createTask(1);
         task.setTaskDescription(new ActivityManager.TaskDescription());
         final TaskInfo info = task.getTaskInfo();
 
@@ -141,19 +139,19 @@
 
     @Test
     public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
-        TestTaskRecordFactory factory = new TestTaskRecordFactory();
-        TaskRecord.setTaskRecordFactory(factory);
+        TestTaskFactory factory = new TestTaskFactory();
+        Task.setTaskFactory(factory);
 
         assertFalse(factory.mCreated);
 
-        TaskRecord.create(null, 0, null, null, null, null);
+        Task.create(null, 0, null, null, null, null);
 
         assertTrue(factory.mCreated);
     }
 
     @Test
     public void testReturnsToHomeStack() throws Exception {
-        final TaskRecord task = createTaskRecord(1);
+        final Task task = createTask(1);
         assertFalse(task.returnsToHomeStack());
         task.intent = null;
         assertFalse(task.returnsToHomeStack());
@@ -198,7 +196,7 @@
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
         final Configuration parentConfig = stack.getConfiguration();
         parentConfig.windowConfiguration.setBounds(parentBounds);
         parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
@@ -237,7 +235,7 @@
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
                 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
-        TaskRecord task = stack.getChildAt(0);
+        Task task = stack.getChildAt(0);
         task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
         DisplayInfo info = new DisplayInfo();
         display.mDisplay.getDisplayInfo(info);
@@ -281,7 +279,7 @@
 
         ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
-        TaskRecord task = stack.getChildAt(0);
+        Task task = stack.getChildAt(0);
         ActivityRecord root = task.getTopActivity();
 
         assertEquals(fullScreenBounds, task.getBounds());
@@ -345,7 +343,7 @@
                 display.getRequestedOverrideConfiguration());
         ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
-        TaskRecord task = stack.getChildAt(0);
+        Task task = stack.getChildAt(0);
         ActivityRecord root = task.getTopActivity();
 
         final WindowContainer parentWindowContainer =
@@ -355,7 +353,7 @@
         doReturn(parentWindowContainer).when(task).getParent();
         doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
 
-        // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
+        // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
         // bounds because its parent says it will handle it at a later time.
         root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
         assertEquals(root, task.getRootActivity());
@@ -365,7 +363,7 @@
 
     @Test
     public void testComputeConfigResourceOverrides() {
-        final TaskRecord task = new TaskBuilder(mSupervisor).build();
+        final Task task = new TaskBuilder(mSupervisor).build();
         final Configuration inOutConfig = new Configuration();
         final Configuration parentConfig = new Configuration();
         final int longSide = 1200;
@@ -434,7 +432,7 @@
         info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
         info.targetActivity = targetClassName;
 
-        final TaskRecord task = TaskRecord.create(mService, 1 /* taskId */, info, intent,
+        final Task task = Task.create(mService, 1 /* taskId */, info, intent,
                 null /* taskDescription */, null /*stack*/);
         assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
                 task.intent.getComponent().getClassName());
@@ -457,7 +455,7 @@
     /** Test that root activity index is reported correctly for several activities in the task. */
     @Test
     public void testFindRootIndex() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
 
@@ -471,7 +469,7 @@
      */
     @Test
     public void testFindRootIndex_finishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add extra two activities and mark the two on the bottom as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -489,7 +487,7 @@
      */
     @Test
     public void testFindRootIndex_effectiveRoot() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
 
@@ -503,7 +501,7 @@
      */
     @Test
     public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
         // one above as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
@@ -522,7 +520,7 @@
      */
     @Test
     public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Set relinquishTaskIdentity for the only activity in the task
         task.getChildAt(0).info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
 
@@ -536,7 +534,7 @@
      */
     @Test
     public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Set relinquishTaskIdentity for all activities in the task
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -547,10 +545,10 @@
                 task.getChildCount() - 1, task.findRootIndex(true /* effectiveRoot*/));
     }
 
-    /** Test that bottom-most activity is reported in {@link TaskRecord#getRootActivity()}. */
+    /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
     @Test
     public void testGetRootActivity() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
 
@@ -559,11 +557,11 @@
     }
 
     /**
-     * Test that first non-finishing activity is reported in {@link TaskRecord#getRootActivity()}.
+     * Test that first non-finishing activity is reported in {@link Task#getRootActivity()}.
      */
     @Test
     public void testGetRootActivity_finishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Add an extra activity on top of the root one
         new ActivityBuilder(mService).setTask(task).build();
         // Mark the root as finishing
@@ -574,11 +572,11 @@
     }
 
     /**
-     * Test that relinquishTaskIdentity flag is ignored in {@link TaskRecord#getRootActivity()}.
+     * Test that relinquishTaskIdentity flag is ignored in {@link Task#getRootActivity()}.
      */
     @Test
     public void testGetRootActivity_relinquishTaskIdentity() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -590,12 +588,12 @@
     }
 
     /**
-     * Test that no activity is reported in {@link TaskRecord#getRootActivity()} when all activities
+     * Test that no activity is reported in {@link Task#getRootActivity()} when all activities
      * in the task are finishing.
      */
     @Test
     public void testGetRootActivity_allFinishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -611,7 +609,7 @@
      */
     @Test
     public void testIsRootActivity() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -628,7 +626,7 @@
      */
     @Test
     public void testIsRootActivity_allFinishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -646,10 +644,10 @@
      */
     @Test
     public void testGetTaskForActivity() {
-        final TaskRecord task0 = getTestTask();
+        final Task task0 = getTestTask();
         final ActivityRecord activity0 = task0.getChildAt(0);
 
-        final TaskRecord task1 = getTestTask();
+        final Task task1 = getTestTask();
         final ActivityRecord activity1 = task1.getChildAt(0);
 
         assertEquals(task0.mTaskId,
@@ -664,7 +662,7 @@
      */
     @Test
     public void testGetTaskForActivity_onlyRoot_finishing() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Make the current root activity finishing
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -687,7 +685,7 @@
      */
     @Test
     public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Make the current root activity relinquish task identity
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
@@ -710,7 +708,7 @@
      */
     @Test
     public void testGetTaskForActivity_notOnlyRoot() {
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         // Mark the bottom-most activity as finishing.
         final ActivityRecord activity0 = task.getChildAt(0);
         activity0.finishing = true;
@@ -731,12 +729,12 @@
     }
 
     /**
-     * Test {@link TaskRecord#updateEffectiveIntent()}.
+     * Test {@link Task#updateEffectiveIntent()}.
      */
     @Test
     public void testUpdateEffectiveIntent() {
         // Test simple case with a single activity.
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         final ActivityRecord activity0 = task.getChildAt(0);
 
         spyOn(task);
@@ -745,13 +743,13 @@
     }
 
     /**
-     * Test {@link TaskRecord#updateEffectiveIntent()} with root activity marked as finishing. This
+     * Test {@link Task#updateEffectiveIntent()} with root activity marked as finishing. This
      * should make the task use the second activity when updating the intent.
      */
     @Test
     public void testUpdateEffectiveIntent_rootFinishing() {
         // Test simple case with a single activity.
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         final ActivityRecord activity0 = task.getChildAt(0);
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
@@ -764,14 +762,14 @@
     }
 
     /**
-     * Test {@link TaskRecord#updateEffectiveIntent()} when all activities are finishing or
+     * Test {@link Task#updateEffectiveIntent()} when all activities are finishing or
      * relinquishing task identity. In this case the root activity should still be used when
      * updating the intent (legacy behavior).
      */
     @Test
     public void testUpdateEffectiveIntent_allFinishing() {
         // Test simple case with a single activity.
-        final TaskRecord task = getTestTask();
+        final Task task = getTestTask();
         final ActivityRecord activity0 = task.getChildAt(0);
         // Mark the bottom-most activity as finishing.
         activity0.finishing = true;
@@ -785,7 +783,7 @@
         verify(task).setIntent(eq(activity0));
     }
 
-    private TaskRecord getTestTask() {
+    private Task getTestTask() {
         final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
         return stack.getChildAt(0);
     }
@@ -796,7 +794,7 @@
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
         ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
                 true /* onTop */);
-        TaskRecord task = new TaskBuilder(mSupervisor).setStack(stack).build();
+        Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
 
         final Configuration parentConfig = stack.getConfiguration();
         parentConfig.windowConfiguration.setAppBounds(parentBounds);
@@ -808,7 +806,7 @@
                 task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
     }
 
-    private byte[] serializeToBytes(TaskRecord r) throws IOException, XmlPullParserException {
+    private byte[] serializeToBytes(Task r) throws IOException, XmlPullParserException {
         try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
             final XmlSerializer serializer = Xml.newSerializer();
             serializer.setOutput(os, "UTF-8");
@@ -823,29 +821,29 @@
         }
     }
 
-    private TaskRecord restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
+    private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
         try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
             final XmlPullParser parser = Xml.newPullParser();
             parser.setInput(reader);
             assertEquals(XmlPullParser.START_TAG, parser.next());
             assertEquals(TASK_TAG, parser.getName());
-            return TaskRecord.restoreFromXml(parser, mService.mStackSupervisor);
+            return Task.restoreFromXml(parser, mService.mStackSupervisor);
         }
     }
 
-    private TaskRecord createTaskRecord(int taskId) {
-        return new TaskRecord(mService, taskId, new Intent(), null, null, null,
+    private Task createTask(int taskId) {
+        return new Task(mService, taskId, new Intent(), null, null, null,
                 ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
                 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
                 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
                 null /*stack*/);
     }
 
-    private static class TestTaskRecordFactory extends TaskRecordFactory {
+    private static class TestTaskFactory extends TaskFactory {
         private boolean mCreated = false;
 
         @Override
-        TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+        Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
                 Intent intent, IVoiceInteractionSession voiceSession,
                 IVoiceInteractor voiceInteractor, ActivityStack stack) {
             mCreated = true;
@@ -853,7 +851,7 @@
         }
 
         @Override
-        TaskRecord create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
+        Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
                 Intent intent, ActivityManager.TaskDescription taskDescription,
                 ActivityStack stack) {
             mCreated = true;
@@ -861,7 +859,7 @@
         }
 
         @Override
-        TaskRecord create(ActivityTaskManagerService service, int taskId, Intent intent,
+        Task create(ActivityTaskManagerService service, int taskId, Intent intent,
                 Intent affinityIntent, String affinity, String rootAffinity,
                 ComponentName realActivity,
                 ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
@@ -879,7 +877,7 @@
         }
 
         @Override
-        TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
+        Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
                 throws IOException, XmlPullParserException {
             mCreated = true;
             return null;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
index 7897047..dbf61db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -45,7 +45,7 @@
 @RunWith(WindowTestRunner.class)
 public class TaskStackContainersTests extends WindowTestsBase {
 
-    private TaskStack mPinnedStack;
+    private ActivityStack mPinnedStack;
 
     @Before
     public void setUp() throws Exception {
@@ -68,8 +68,8 @@
     @Test
     public void testStackPositionChildAt() {
         // Test that always-on-top stack can't be moved to position other than top.
-        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
-        final TaskStack stack2 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent);
 
         final WindowContainer taskStackContainer = stack1.getParent();
 
@@ -93,7 +93,7 @@
     @Test
     public void testStackPositionBelowPinnedStack() {
         // Test that no stack can be above pinned stack.
-        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent);
 
         final WindowContainer taskStackContainer = stack1.getParent();
 
@@ -113,7 +113,7 @@
     @Test
     public void testDisplayPositionWithPinnedStack() {
         // The display contains pinned stack that was added in {@link #setUp}.
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
 
         // Add another display at top.
@@ -121,7 +121,7 @@
                 false /* includingParents */);
 
         // Move the task of {@code mDisplayContent} to top.
-        stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task, true /* includingParents */);
+        stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */);
         final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent);
 
         assertEquals("The testing DisplayContent should be moved to top with task",
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
index a9d0ea1..5877041 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackTests.java
@@ -41,7 +41,7 @@
 import org.junit.runner.RunWith;
 
 /**
- * Tests for the {@link TaskStack} class.
+ * Tests for the {@link ActivityStack} class.
  *
  * Build/Install/Run:
  *  atest WmTests:TaskStackTests
@@ -53,24 +53,24 @@
 
     @Test
     public void testStackPositionChildAt() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         final Task task2 = createTaskInStack(stack, 1 /* userId */);
 
         // Current user task should be moved to top.
-        stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task1, false /* includingParents */);
+        stack.positionChildAt(WindowContainer.POSITION_TOP, task1, false /* includingParents */);
         assertEquals(stack.mChildren.get(0), task2);
         assertEquals(stack.mChildren.get(1), task1);
 
         // Non-current user won't be moved to top.
-        stack.positionChildAt(WindowContainer.POSITION_TOP, (TaskRecord) task2, false /* includingParents */);
+        stack.positionChildAt(WindowContainer.POSITION_TOP, task2, false /* includingParents */);
         assertEquals(stack.mChildren.get(0), task2);
         assertEquals(stack.mChildren.get(1), task1);
     }
 
     @Test
     public void testClosingAppDifferentStackOrientation() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         ActivityRecord activity1 =
                 WindowTestUtils.createTestActivityRecord(mDisplayContent);
@@ -90,7 +90,7 @@
 
     @Test
     public void testMoveTaskToBackDifferentStackOrientation() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack, 0 /* userId */);
         ActivityRecord activity1 =
                 WindowTestUtils.createTestActivityRecord(mDisplayContent);
@@ -110,7 +110,7 @@
 
     @Test
     public void testStackRemoveImmediately() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
         assertEquals(stack, task.getTaskStack());
 
@@ -122,7 +122,7 @@
 
     @Test
     public void testRemoveContainer() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
 
         assertNotNull(stack);
@@ -138,7 +138,7 @@
 
     @Test
     public void testRemoveContainer_deferRemoval() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack, 0 /* userId */);
 
         // Stack removal is deferred if one of its child is animating.
@@ -160,15 +160,15 @@
     @Test
     public void testReparent() {
         // Create first stack on primary display.
-        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task1 = createTaskInStack(stack1, 0 /* userId */);
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
-        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final ActivityStack stack2 = createTaskStackOnDisplay(dc);
 
         // Reparent
-        stack1.reparent(dc.getDisplayId(), new Rect(), true /* onTop */);
+        stack1.reparent(dc, true /* onTop */);
         assertEquals(dc, stack1.getDisplayContent());
         final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
         final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
@@ -178,10 +178,11 @@
 
     @Test
     public void testStackOutset() {
-        final TaskStack stack = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
         final int stackOutset = 10;
         spyOn(stack);
         doReturn(stackOutset).when(stack).getStackOutset();
+        doReturn(true).when(stack).inMultiWindowMode();
 
         final Rect stackBounds = new Rect(200, 200, 800, 1000);
         // Update surface position and size by the given bounds.
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index cb2e1e0..9f85e1c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -51,7 +51,7 @@
 
     @Test
     public void testRemoveContainer() {
-        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final ActivityRecord activity =
                 WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
@@ -65,7 +65,7 @@
 
     @Test
     public void testRemoveContainer_deferRemoval() {
-        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stackController1, 0 /* userId */);
         final ActivityRecord activity =
                 WindowTestUtils.createActivityRecordInTask(mDisplayContent, task);
@@ -87,9 +87,9 @@
 
     @Test
     public void testReparent() {
-        final TaskStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stackController1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stackController1, 0 /* userId */);
-        final TaskStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stackController2 = createTaskStackOnDisplay(mDisplayContent);
         final Task task2 = createTaskInStack(stackController2, 0 /* userId */);
 
         boolean gotException = false;
@@ -103,11 +103,10 @@
         gotException = false;
         try {
             task.reparent(null, 0, false/* moveParents */, "testReparent");
-        } catch (IllegalArgumentException e) {
+        } catch (Exception e) {
             gotException = true;
         }
-        assertTrue("Should not be able to reparent to a stack that doesn't exist",
-                gotException);
+        assertTrue("Should not be able to reparent to a stack that doesn't exist", gotException);
 
         task.reparent(stackController2, 0, false/* moveParents */, "testReparent");
         assertEquals(stackController2, task.getParent());
@@ -118,13 +117,13 @@
     @Test
     public void testReparent_BetweenDisplays() {
         // Create first stack on primary display.
-        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack1, 0 /* userId */);
         assertEquals(mDisplayContent, stack1.getDisplayContent());
 
         // Create second display and put second stack on it.
         final DisplayContent dc = createNewDisplay();
-        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final ActivityStack stack2 = createTaskStackOnDisplay(dc);
         final Task task2 = createTaskInStack(stack2, 0 /* userId */);
         // Reparent and check state
         task.reparent(stack2, 0, false /* moveParents */, "testReparent_BetweenDisplays");
@@ -136,7 +135,7 @@
 
     @Test
     public void testBounds() {
-        final TaskStack stack1 = createTaskStackOnDisplay(mDisplayContent);
+        final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent);
         final Task task = createTaskInStack(stack1, 0 /* userId */);
 
         // Check that setting bounds also updates surface position
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/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 8536448..8140045 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -221,6 +221,32 @@
     }
 
     @Test
+    public void testRemoveImmediatelyClearsLastSurfacePosition() {
+        reset(mTransaction);
+        try (MockSurfaceBuildingContainer top = new MockSurfaceBuildingContainer(mWm)) {
+            final WindowContainer<WindowContainer> child1 = new WindowContainer(mWm);
+            child1.setBounds(1, 1, 10, 10);
+
+            top.addChild(child1, 0);
+            assertEquals(1, child1.getLastSurfacePosition().x);
+            assertEquals(1, child1.getLastSurfacePosition().y);
+
+            WindowContainer child11 = new WindowContainer(mWm);
+            child1.addChild(child11, 0);
+
+            child1.setBounds(2, 2, 20, 20);
+            assertEquals(2, child1.getLastSurfacePosition().x);
+            assertEquals(2, child1.getLastSurfacePosition().y);
+
+            child1.removeImmediately();
+            assertEquals(0, child1.getLastSurfacePosition().x);
+            assertEquals(0, child1.getLastSurfacePosition().y);
+            assertEquals(0, child11.getLastSurfacePosition().x);
+            assertEquals(0, child11.getLastSurfacePosition().y);
+        }
+    }
+
+    @Test
     public void testAddChildByIndex() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
@@ -314,32 +340,6 @@
     }
 
     @Test
-    public void testPositionChildAtInvalid() {
-        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
-        final TestWindowContainer root = builder.setLayer(0).build();
-
-        final TestWindowContainer child1 = root.addChildWindow();
-
-        boolean gotException = false;
-        try {
-            // Check response to negative position.
-            root.positionChildAt(-1, child1, false /* includingParents */);
-        } catch (IllegalArgumentException e) {
-            gotException = true;
-        }
-        assertTrue(gotException);
-
-        gotException = false;
-        try {
-            // Check response to position that's bigger than child number.
-            root.positionChildAt(3, child1, false /* includingParents */);
-        } catch (IllegalArgumentException e) {
-            gotException = true;
-        }
-        assertTrue(gotException);
-    }
-
-    @Test
     public void testIsAnimating_TransitionFlag() {
         final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
         final TestWindowContainer root = builder.setLayer(0).build();
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 98d73ba..9e0d3a7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -222,8 +222,7 @@
         final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow");
         final WindowState imeWindow = createWindow(null, TYPE_INPUT_METHOD, "imeWindow");
 
-        // Setting FLAG_NOT_FOCUSABLE without FLAG_ALT_FOCUSABLE_IM prevents the window from being
-        // an IME target.
+        // Setting FLAG_NOT_FOCUSABLE prevents the window from being an IME target.
         appWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
         imeWindow.mAttrs.flags |= FLAG_NOT_FOCUSABLE;
 
@@ -231,7 +230,7 @@
         appWindow.setHasSurface(true);
         imeWindow.setHasSurface(true);
 
-        // Windows without flags (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) can't be IME targets
+        // Windows with FLAG_NOT_FOCUSABLE can't be IME targets
         assertFalse(appWindow.canBeImeTarget());
         assertFalse(imeWindow.canBeImeTarget());
 
@@ -239,11 +238,17 @@
         appWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
         imeWindow.mAttrs.flags |= (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM);
 
-        // Visible app window with flags can be IME target while an IME window can never be an IME
-        // target regardless of its visibility or flags.
-        assertTrue(appWindow.canBeImeTarget());
+        // Visible app window with flags FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM can't be IME
+        // target while an IME window can never be an IME target regardless of its visibility
+        // or flags.
+        assertFalse(appWindow.canBeImeTarget());
         assertFalse(imeWindow.canBeImeTarget());
 
+        appWindow.mAttrs.flags &= ~FLAG_ALT_FOCUSABLE_IM;
+        assertFalse(appWindow.canBeImeTarget());
+        appWindow.mAttrs.flags &= ~FLAG_NOT_FOCUSABLE;
+        assertTrue(appWindow.canBeImeTarget());
+
         // Make windows invisible
         appWindow.hideLw(false /* doAnimation */);
         imeWindow.hideLw(false /* doAnimation */);
@@ -256,7 +261,7 @@
         // minimized and home stack is resizable, so that we should ignore input for the stack.
         final DockedStackDividerController controller =
                 mDisplayContent.getDockedDividerController();
-        final TaskStack stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+        final ActivityStack stack = createTaskStackOnDisplay(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
                 ACTIVITY_TYPE_STANDARD, mDisplayContent);
         spyOn(appWindow);
         spyOn(controller);
@@ -510,12 +515,12 @@
         window.setShowToOwnerOnlyLocked(true);
 
         mWm.mCurrentUserId = 1;
-        window.switchUser();
+        window.switchUser(mWm.mCurrentUserId);
         assertFalse(window.isVisible());
         assertFalse(window.isVisibleByPolicy());
 
         mWm.mCurrentUserId = 0;
-        window.switchUser();
+        window.switchUser(mWm.mCurrentUserId);
         assertTrue(window.isVisible());
         assertTrue(window.isVisibleByPolicy());
     }
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 3f32e33..797a6bc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -17,12 +17,10 @@
 package com.android.server.wm;
 
 import static android.app.AppOpsManager.OP_NONE;
-import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
-import android.app.ActivityManager;
 import android.os.IBinder;
 import android.view.IWindow;
 import android.view.WindowManager;
@@ -34,13 +32,13 @@
  */
 class WindowTestUtils {
 
-    /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
-    static Task createTaskInStack(WindowManagerService service, TaskStack stack, int userId) {
+    /** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
+    static Task createTaskInStack(WindowManagerService service, ActivityStack stack, int userId) {
         synchronized (service.mGlobalLock) {
-            final TaskRecord task = new ActivityTestsBase.TaskBuilder(
-                    stack.mActivityStack.mStackSupervisor)
+            final Task task = new ActivityTestsBase.TaskBuilder(
+                    stack.mStackSupervisor)
                     .setUserId(userId)
-                    .setStack(stack.mActivityStack)
+                    .setStack(stack)
                     .build();
             return task;
         }
@@ -60,7 +58,7 @@
                     .setStack(stack)
                     .setCreateTask(true)
                     .build();
-            postCreateActivitySetup(activity, stack.mTaskStack.getDisplayContent());
+            postCreateActivitySetup(activity, stack.getDisplayContent());
             return activity;
         }
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index c3f59eb..0da9dc4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -41,7 +41,6 @@
 import static org.mockito.Mockito.mock;
 
 import android.content.Context;
-import android.content.res.Configuration;
 import android.util.Log;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -210,8 +209,8 @@
 
     ActivityRecord createTestActivityRecord(DisplayContent dc, int
             windowingMode, int activityType) {
-        final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
-        return WindowTestUtils.createTestActivityRecord(stack.mActivityStack);
+        final ActivityStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc);
+        return WindowTestUtils.createTestActivityRecord(stack);
     }
 
     WindowState createWindow(WindowState parent, int type, String name) {
@@ -314,28 +313,25 @@
         }
     }
 
-    /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */
-    TaskStack createTaskStackOnDisplay(DisplayContent dc) {
-        synchronized (mWm.mGlobalLock) {
-            return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
-        }
+    /** Creates a {@link ActivityStack} and adds it to the specified {@link DisplayContent}. */
+    ActivityStack createTaskStackOnDisplay(DisplayContent dc) {
+        return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc);
     }
 
-    TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
+    ActivityStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) {
         synchronized (mWm.mGlobalLock) {
-            final ActivityStack stack = new ActivityTestsBase.StackBuilder(
+            return new ActivityTestsBase.StackBuilder(
                     dc.mWmService.mAtmService.mRootActivityContainer)
                     .setDisplay(dc.mActivityDisplay)
                     .setWindowingMode(windowingMode)
                     .setActivityType(activityType)
                     .setCreateActivity(false)
                     .build();
-            return stack.mTaskStack;
         }
     }
 
-    /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
-    Task createTaskInStack(TaskStack stack, int userId) {
+    /** Creates a {@link Task} and adds it to the specified {@link ActivityStack}. */
+    Task createTaskInStack(ActivityStack stack, int userId) {
         return WindowTestUtils.createTaskInStack(mWm, stack, userId);
     }
 
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 047fcec..9967beb 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -488,7 +488,7 @@
      *  Opens the specified USB device
      */
     public ParcelFileDescriptor openDevice(String deviceAddress,
-            UsbUserPermissionManager permissions, String packageName, int uid) {
+            UsbUserPermissionManager permissions, String packageName, int pid, int uid) {
         synchronized (mLock) {
             if (isBlackListed(deviceAddress)) {
                 throw new SecurityException("USB device is on a restricted bus");
@@ -500,7 +500,7 @@
                         "device " + deviceAddress + " does not exist or is restricted");
             }
 
-            permissions.checkPermission(device, packageName, uid);
+            permissions.checkPermission(device, packageName, pid, uid);
             return nativeOpenDevice(deviceAddress);
         }
     }
diff --git a/services/usb/java/com/android/server/usb/UsbSerialReader.java b/services/usb/java/com/android/server/usb/UsbSerialReader.java
index 3151679..86016bb 100644
--- a/services/usb/java/com/android/server/usb/UsbSerialReader.java
+++ b/services/usb/java/com/android/server/usb/UsbSerialReader.java
@@ -93,7 +93,7 @@
                         int userId = UserHandle.getUserId(uid);
                         if (mDevice instanceof UsbDevice) {
                             mPermissionManager.getPermissionsForUser(userId)
-                                    .checkPermission((UsbDevice) mDevice, packageName, uid);
+                                    .checkPermission((UsbDevice) mDevice, packageName, pid, uid);
                         } else {
                             mPermissionManager.getPermissionsForUser(userId)
                                     .checkPermission((UsbAccessory) mDevice, uid);
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 0493637..27531949 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -262,6 +262,7 @@
         if (mHostManager != null) {
             if (deviceName != null) {
                 int uid = Binder.getCallingUid();
+                int pid = Binder.getCallingPid();
                 int user = UserHandle.getUserId(uid);
 
                 long ident = clearCallingIdentity();
@@ -269,7 +270,7 @@
                     synchronized (mLock) {
                         if (mUserManager.isSameProfileGroup(user, mCurrentUserId)) {
                             fd = mHostManager.openDevice(deviceName, getPermissionsForUser(user),
-                                    packageName, uid);
+                                    packageName, pid, uid);
                         } else {
                             Slog.w(TAG, "Cannot open " + deviceName + " for user " + user
                                     + " as user is not active.");
@@ -469,11 +470,12 @@
     @Override
     public boolean hasDevicePermission(UsbDevice device, String packageName) {
         final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
         final int userId = UserHandle.getUserId(uid);
 
         final long token = Binder.clearCallingIdentity();
         try {
-            return getPermissionsForUser(userId).hasPermission(device, packageName, uid);
+            return getPermissionsForUser(userId).hasPermission(device, packageName, pid, uid);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
@@ -495,11 +497,12 @@
     @Override
     public void requestDevicePermission(UsbDevice device, String packageName, PendingIntent pi) {
         final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
         final int userId = UserHandle.getUserId(uid);
 
         final long token = Binder.clearCallingIdentity();
         try {
-            getPermissionsForUser(userId).requestPermission(device, packageName, pi, uid);
+            getPermissionsForUser(userId).requestPermission(device, packageName, pi, pid, uid);
         } finally {
             Binder.restoreCallingIdentity(token);
         }
diff --git a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index e700f19..58f5484 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -186,12 +186,14 @@
      * Returns true if package with uid has permission to access the device.
      *
      * @param device to check permission for
+     * @param pid to check permission for
      * @param uid to check permission for
      * @return {@code true} if package with uid has permission
      */
-    boolean hasPermission(@NonNull UsbDevice device, @NonNull String packageName, int uid) {
+    boolean hasPermission(@NonNull UsbDevice device, @NonNull String packageName, int pid,
+            int uid) {
         if (isCameraDevicePresent(device)) {
-            if (!isCameraPermissionGranted(packageName, uid)) {
+            if (!isCameraPermissionGranted(packageName, pid, uid)) {
                 return false;
             }
         }
@@ -615,10 +617,11 @@
      * Check for camera permission of the calling process.
      *
      * @param packageName Package name of the caller.
+     * @param pid         Linux pid of the calling process.
      * @param uid         Linux uid of the calling process.
      * @return True in case camera permission is available, False otherwise.
      */
-    private boolean isCameraPermissionGranted(String packageName, int uid) {
+    private boolean isCameraPermissionGranted(String packageName, int pid, int uid) {
         int targetSdkVersion = android.os.Build.VERSION_CODES.P;
         try {
             ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
@@ -634,7 +637,7 @@
         }
 
         if (targetSdkVersion >= android.os.Build.VERSION_CODES.P) {
-            int allowed = mContext.checkCallingPermission(android.Manifest.permission.CAMERA);
+            int allowed = mContext.checkPermission(android.Manifest.permission.CAMERA, pid, uid);
             if (android.content.pm.PackageManager.PERMISSION_DENIED == allowed) {
                 Slog.i(TAG, "Camera permission required for USB video class devices");
                 return false;
@@ -644,8 +647,8 @@
         return true;
     }
 
-    public void checkPermission(UsbDevice device, String packageName, int uid) {
-        if (!hasPermission(device, packageName, uid)) {
+    public void checkPermission(UsbDevice device, String packageName, int pid, int uid) {
+        if (!hasPermission(device, packageName, pid, uid)) {
             throw new SecurityException("User has not given " + uid + "/" + packageName
                     + " permission to access device " + device.getDeviceName());
         }
@@ -678,11 +681,12 @@
         requestPermissionDialog(device, accessory, canBeDefault, packageName, uid, mContext, pi);
     }
 
-    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int uid) {
+    public void requestPermission(UsbDevice device, String packageName, PendingIntent pi, int pid,
+            int uid) {
         Intent intent = new Intent();
 
         // respond immediately if permission has already been granted
-        if (hasPermission(device, packageName, uid)) {
+        if (hasPermission(device, packageName, pid, uid)) {
             intent.putExtra(UsbManager.EXTRA_DEVICE, device);
             intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
             try {
@@ -693,7 +697,7 @@
             return;
         }
         if (isCameraDevicePresent(device)) {
-            if (!isCameraPermissionGranted(packageName, uid)) {
+            if (!isCameraPermissionGranted(packageName, pid, uid)) {
                 intent.putExtra(UsbManager.EXTRA_DEVICE, device);
                 intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false);
                 try {
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 60290e3..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;
@@ -512,8 +515,8 @@
 
         /**
          * Indicates the call used Assisted Dialing.
-         * See also {@link Connection#PROPERTY_ASSISTED_DIALING_USED}
-         * @hide
+         *
+         * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
          */
         public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
 
@@ -1181,7 +1184,8 @@
         public void onConferenceableCallsChanged(Call call, List<Call> conferenceableCalls) {}
 
         /**
-         * Invoked when a {@link Call} receives an event from its associated {@link Connection}.
+         * Invoked when a {@link Call} receives an event from its associated {@link Connection} or
+         * {@link Conference}.
          * <p>
          * Where possible, the Call should make an attempt to handle {@link Connection} events which
          * are part of the {@code android.telecom.*} namespace.  The Call should ignore any events
@@ -1189,7 +1193,8 @@
          * possible that a {@link ConnectionService} has defined its own Connection events which a
          * Call is not aware of.
          * <p>
-         * See {@link Connection#sendConnectionEvent(String, Bundle)}.
+         * See {@link Connection#sendConnectionEvent(String, Bundle)},
+         * {@link Conference#sendConferenceEvent(String, Bundle)}.
          *
          * @param call The {@code Call} receiving the event.
          * @param event The event.
@@ -2130,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/Conference.java b/telecomm/java/android/telecom/Conference.java
index d90f46d..58abf00 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -50,7 +50,7 @@
     public static final long CONNECT_TIME_NOT_SPECIFIED = 0;
 
     /** @hide */
-    public abstract static class Listener {
+    abstract static class Listener {
         public void onStateChanged(Conference conference, int oldState, int newState) {}
         public void onDisconnected(Conference conference, DisconnectCause disconnectCause) {}
         public void onConnectionAdded(Conference conference, Connection connection) {}
@@ -121,11 +121,17 @@
 
     /**
      * Returns the telecom internal call ID associated with this conference.
+     * <p>
+     * Note: This is ONLY used for debugging purposes so that the Telephony stack can better
+     * associate logs in Telephony with those in Telecom.
+     * The ID returned should not be used for any other purpose.
      *
      * @return The telecom call ID.
      * @hide
      */
-    public final String getTelecomCallId() {
+    @SystemApi
+    @TestApi
+    public final @NonNull String getTelecomCallId() {
         return mTelecomCallId;
     }
 
@@ -187,55 +193,6 @@
     }
 
     /**
-     * Whether the given capabilities support the specified capability.
-     *
-     * @param capabilities A capability bit field.
-     * @param capability The capability to check capabilities for.
-     * @return Whether the specified capability is supported.
-     * @hide
-     */
-    public static boolean can(int capabilities, int capability) {
-        return (capabilities & capability) != 0;
-    }
-
-    /**
-     * Whether the capabilities of this {@code Connection} supports the specified capability.
-     *
-     * @param capability The capability to check capabilities for.
-     * @return Whether the specified capability is supported.
-     * @hide
-     */
-    public boolean can(int capability) {
-        return can(mConnectionCapabilities, capability);
-    }
-
-    /**
-     * Removes the specified capability from the set of capabilities of this {@code Conference}.
-     *
-     * @param capability The capability to remove from the set.
-     * @hide
-     */
-    public void removeCapability(int capability) {
-        int newCapabilities = mConnectionCapabilities;
-        newCapabilities &= ~capability;
-
-        setConnectionCapabilities(newCapabilities);
-    }
-
-    /**
-     * Adds the specified capability to the set of capabilities of this {@code Conference}.
-     *
-     * @param capability The capability to add to the set.
-     * @hide
-     */
-    public void addCapability(int capability) {
-        int newCapabilities = mConnectionCapabilities;
-        newCapabilities |= capability;
-
-        setConnectionCapabilities(newCapabilities);
-    }
-
-    /**
      * @return The audio state of the conference, describing how its audio is currently
      *         being routed by the system. This is {@code null} if this Conference
      *         does not directly know about its audio state.
@@ -554,7 +511,7 @@
      * @return This conference.
      * @hide
      */
-    public final Conference addListener(Listener listener) {
+    final Conference addListener(Listener listener) {
         mListeners.add(listener);
         return this;
     }
@@ -566,7 +523,7 @@
      * @return This conference.
      * @hide
      */
-    public final Conference removeListener(Listener listener) {
+    final Conference removeListener(Listener listener) {
         mListeners.remove(listener);
         return this;
     }
@@ -588,20 +545,6 @@
     }
 
     /**
-     * Updates RIL voice radio technology used for current conference after its creation.
-     *
-     * @hide
-     */
-    public void updateCallRadioTechAfterCreation() {
-        final Connection primaryConnection = getPrimaryConnection();
-        if (primaryConnection != null) {
-            setCallRadioTech(primaryConnection.getCallRadioTech());
-        } else {
-            Log.w(this, "No primary connection found while updateCallRadioTechAfterCreation");
-        }
-    }
-
-    /**
      * @hide
      * @deprecated Use {@link #setConnectionTime}.
      */
@@ -669,49 +612,24 @@
      * Retrieves the connection start time of the {@link Conference}, if specified.  A value of
      * {@link #CONNECT_TIME_NOT_SPECIFIED} indicates that Telecom should determine the start time
      * of the conference.
-     *
+     * <p>
      * This is based on the value of {@link SystemClock#elapsedRealtime()} to ensure that it is not
      * impacted by wall clock changes (user initiated, network initiated, time zone change, etc).
+     * <p>
+     * Note: This is only exposed for use by the Telephony framework which needs it to copy
+     * conference start times among conference participants.  It is exposed as a system API since it
+     * has no general use other than to the Telephony framework.
      *
      * @return The elapsed time at which the {@link Conference} was connected.
      * @hide
      */
+    @SystemApi
+    @TestApi
     public final long getConnectionStartElapsedRealTime() {
         return mConnectionStartElapsedRealTime;
     }
 
     /**
-     * Sets RIL voice radio technology used for current conference.
-     *
-     * @param vrat the RIL voice radio technology used for current conference,
-     *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
-     *
-     * @hide
-     */
-    public final void setCallRadioTech(@RilRadioTechnology int vrat) {
-        putExtra(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
-                ServiceState.rilRadioTechnologyToNetworkType(vrat));
-    }
-
-    /**
-     * Returns RIL voice radio technology used for current conference.
-     *
-     * @return the RIL voice radio technology used for current conference,
-     *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
-     *
-     * @hide
-     */
-    public final @RilRadioTechnology int getCallRadioTech() {
-        int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        Bundle extras = getExtras();
-        if (extras != null) {
-            voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN);
-        }
-        return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
-    }
-
-    /**
      * Inform this Conference that the state of its audio output has been changed externally.
      *
      * @param state The new audio state.
@@ -970,11 +888,15 @@
      * single-party call when the participant count drops to 1.  Although the dialer/phone app
      * could perform this trickery, it makes sense to do this in Telephony since a fix there will
      * ensure that bluetooth head units, auto and wearable apps all behave consistently.
+     * <p>
+     * This API is intended for use by the platform Telephony stack only.
      *
      * @param isConference {@code true} if this {@link Conference} should be treated like a
      *      conference call, {@code false} if it should be treated like a single-party call.
      * @hide
      */
+    @SystemApi
+    @TestApi
     public void setConferenceState(boolean isConference) {
         for (Listener l : mListeners) {
             l.onConferenceStateChanged(this, isConference);
@@ -984,13 +906,19 @@
     /**
      * Sets the address of this {@link Conference}.  Used when {@link #setConferenceState(boolean)}
      * is called to mark a conference temporarily as NOT a conference.
+     * <p>
+     * Note: This is a Telephony-specific implementation detail related to IMS conferences.  It is
+     * not intended for use outside of the Telephony stack.
      *
      * @param address The new address.
      * @param presentation The presentation requirements for the address.
      *        See {@link TelecomManager} for valid values.
      * @hide
      */
-    public final void setAddress(Uri address, int presentation) {
+    @SystemApi
+    @TestApi
+    public final void setAddress(@NonNull Uri address,
+            @TelecomManager.Presentation int presentation) {
         Log.d(this, "setAddress %s", address);
         mAddress = address;
         mAddressPresentation = presentation;
@@ -1056,13 +984,19 @@
      * Sets the caller display name (CNAP) of this {@link Conference}.  Used when
      * {@link #setConferenceState(boolean)} is called to mark a conference temporarily as NOT a
      * conference.
+     * <p>
+     * Note: This is a Telephony-specific implementation detail related to IMS conferences.  It is
+     * not intended for use outside of the Telephony stack.
      *
      * @param callerDisplayName The new display name.
      * @param presentation The presentation requirements for the handle.
      *        See {@link TelecomManager} for valid values.
      * @hide
      */
-    public final void setCallerDisplayName(String callerDisplayName, int presentation) {
+    @SystemApi
+    @TestApi
+    public final void setCallerDisplayName(@NonNull String callerDisplayName,
+            @TelecomManager.Presentation int presentation) {
         Log.d(this, "setCallerDisplayName %s", callerDisplayName);
         mCallerDisplayName = callerDisplayName;
         mCallerDisplayNamePresentation = presentation;
@@ -1089,10 +1023,15 @@
     }
 
     /**
-     * See {@link Connection#sendConnectionEvent(String, Bundle)}
-     * @hide
+     * Sends an event associated with this {@code Conference} with associated event extras to the
+     * {@link InCallService} (note: this is identical in concept to
+     * {@link Connection#sendConnectionEvent(String, Bundle)}).
+     * @see Connection#sendConnectionEvent(String, Bundle)
+     *
+     * @param event The connection event.
+     * @param extras Optional bundle containing extra information associated with the event.
      */
-    public void sendConnectionEvent(String event, Bundle extras) {
+    public void sendConferenceEvent(@NonNull String event, @Nullable Bundle extras) {
         for (Listener l : mListeners) {
             l.onConnectionEvent(this, event, extras);
         }
diff --git a/telecomm/java/android/telecom/ConferenceParticipant.java b/telecomm/java/android/telecom/ConferenceParticipant.java
deleted file mode 100644
index 5e4818a..0000000
--- a/telecomm/java/android/telecom/ConferenceParticipant.java
+++ /dev/null
@@ -1,348 +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 android.telecom;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.PhoneConstants;
-
-/**
- * Parcelable representation of a participant's state in a conference call.
- * @hide
- */
-public class ConferenceParticipant implements Parcelable {
-
-    /**
-     * RFC5767 states that a SIP URI with an unknown number should use an address of
-     * {@code anonymous@anonymous.invalid}.  E.g. the host name is anonymous.invalid.
-     */
-    private static final String ANONYMOUS_INVALID_HOST = "anonymous.invalid";
-    /**
-     * The conference participant's handle (e.g., phone number).
-     */
-    private final Uri mHandle;
-
-    /**
-     * The display name for the participant.
-     */
-    private final String mDisplayName;
-
-    /**
-     * The endpoint Uri which uniquely identifies this conference participant.  E.g. for an IMS
-     * conference call, this is the endpoint URI for the participant on the IMS conference server.
-     */
-    private final Uri mEndpoint;
-
-    /**
-     * The state of the participant in the conference.
-     *
-     * @see android.telecom.Connection
-     */
-    private final int mState;
-
-    /**
-     * The connect time of the participant.
-     */
-    private long mConnectTime;
-
-    /**
-     * The connect elapsed time of the participant.
-     */
-    private long mConnectElapsedTime;
-
-    /**
-     * The direction of the call;
-     * {@link Call.Details#DIRECTION_INCOMING} for incoming calls, or
-     * {@link Call.Details#DIRECTION_OUTGOING} for outgoing calls.
-     */
-    private int mCallDirection;
-
-    /**
-     * Creates an instance of {@code ConferenceParticipant}.
-     *
-     * @param handle      The conference participant's handle (e.g., phone number).
-     * @param displayName The display name for the participant.
-     * @param endpoint    The enpoint Uri which uniquely identifies this conference participant.
-     * @param state       The state of the participant in the conference.
-     * @param callDirection The direction of the call (incoming/outgoing).
-     */
-    public ConferenceParticipant(Uri handle, String displayName, Uri endpoint, int state,
-            int callDirection) {
-        mHandle = handle;
-        mDisplayName = displayName;
-        mEndpoint = endpoint;
-        mState = state;
-        mCallDirection = callDirection;
-    }
-
-    /**
-     * Responsible for creating {@code ConferenceParticipant} objects for deserialized Parcels.
-     */
-    public static final @android.annotation.NonNull Parcelable.Creator<ConferenceParticipant> CREATOR =
-            new Parcelable.Creator<ConferenceParticipant>() {
-
-                @Override
-                public ConferenceParticipant createFromParcel(Parcel source) {
-                    ClassLoader classLoader = ParcelableCall.class.getClassLoader();
-                    Uri handle = source.readParcelable(classLoader);
-                    String displayName = source.readString();
-                    Uri endpoint = source.readParcelable(classLoader);
-                    int state = source.readInt();
-                    long connectTime = source.readLong();
-                    long elapsedRealTime = source.readLong();
-                    int callDirection = source.readInt();
-                    ConferenceParticipant participant =
-                            new ConferenceParticipant(handle, displayName, endpoint, state,
-                                    callDirection);
-                    participant.setConnectTime(connectTime);
-                    participant.setConnectElapsedTime(elapsedRealTime);
-                    participant.setCallDirection(callDirection);
-                    return participant;
-                }
-
-                @Override
-                public ConferenceParticipant[] newArray(int size) {
-                    return new ConferenceParticipant[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /**
-     * Determines the number presentation for a conference participant.  Per RFC5767, if the host
-     * name contains {@code anonymous.invalid} we can assume that there is no valid caller ID
-     * information for the caller, otherwise we'll assume that the URI can be shown.
-     *
-     * @return The number presentation.
-     */
-    @VisibleForTesting
-    public int getParticipantPresentation() {
-        Uri address = getHandle();
-        if (address == null) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
-
-        String number = address.getSchemeSpecificPart();
-        // If no number, bail early and set restricted presentation.
-        if (TextUtils.isEmpty(number)) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
-        // Per RFC3261, the host name portion can also potentially include extra information:
-        // E.g. sip:anonymous1@anonymous.invalid;legid=1
-        // In this case, hostName will be anonymous.invalid and there is an extra parameter for
-        // legid=1.
-        // Parameters are optional, and the address (e.g. test@test.com) will always be the first
-        // part, with any parameters coming afterwards.
-        String [] hostParts = number.split("[;]");
-        String addressPart = hostParts[0];
-
-        // Get the number portion from the address part.
-        // This will typically be formatted similar to: 6505551212@test.com
-        String [] numberParts = addressPart.split("[@]");
-
-        // If we can't parse the host name out of the URI, then there is probably other data
-        // present, and is likely a valid SIP URI.
-        if (numberParts.length != 2) {
-            return PhoneConstants.PRESENTATION_ALLOWED;
-        }
-        String hostName = numberParts[1];
-
-        // If the hostname portion of the SIP URI is the invalid host string, presentation is
-        // restricted.
-        if (hostName.equals(ANONYMOUS_INVALID_HOST)) {
-            return PhoneConstants.PRESENTATION_RESTRICTED;
-        }
-
-        return PhoneConstants.PRESENTATION_ALLOWED;
-    }
-
-    /**
-     * Writes the {@code ConferenceParticipant} to a parcel.
-     *
-     * @param dest The Parcel in which the object should be written.
-     * @param flags Additional flags about how the object should be written.
-     */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeParcelable(mHandle, 0);
-        dest.writeString(mDisplayName);
-        dest.writeParcelable(mEndpoint, 0);
-        dest.writeInt(mState);
-        dest.writeLong(mConnectTime);
-        dest.writeLong(mConnectElapsedTime);
-        dest.writeInt(mCallDirection);
-    }
-
-    /**
-     * Builds a string representation of this instance.
-     *
-     * @return String representing the conference participant.
-     */
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[ConferenceParticipant Handle: ");
-        sb.append(Log.pii(mHandle));
-        sb.append(" DisplayName: ");
-        sb.append(Log.pii(mDisplayName));
-        sb.append(" Endpoint: ");
-        sb.append(Log.pii(mEndpoint));
-        sb.append(" State: ");
-        sb.append(Connection.stateToString(mState));
-        sb.append(" ConnectTime: ");
-        sb.append(getConnectTime());
-        sb.append(" ConnectElapsedTime: ");
-        sb.append(getConnectElapsedTime());
-        sb.append(" Direction: ");
-        sb.append(getCallDirection() == Call.Details.DIRECTION_INCOMING ? "Incoming" : "Outgoing");
-        sb.append("]");
-        return sb.toString();
-    }
-
-    /**
-     * The conference participant's handle (e.g., phone number).
-     */
-    public Uri getHandle() {
-        return mHandle;
-    }
-
-    /**
-     * The display name for the participant.
-     */
-    public String getDisplayName() {
-        return mDisplayName;
-    }
-
-    /**
-     * The enpoint Uri which uniquely identifies this conference participant.  E.g. for an IMS
-     * conference call, this is the endpoint URI for the participant on the IMS conference server.
-     */
-    public Uri getEndpoint() {
-        return mEndpoint;
-    }
-
-    /**
-     * The state of the participant in the conference.
-     *
-     * @see android.telecom.Connection
-     */
-    public int getState() {
-        return mState;
-    }
-
-    /**
-     * The connect time of the participant to the conference.
-     */
-    public long getConnectTime() {
-        return mConnectTime;
-    }
-
-    public void setConnectTime(long connectTime) {
-        this.mConnectTime = connectTime;
-    }
-
-    /**
-     * The connect elapsed time of the participant to the conference.
-     */
-    public long getConnectElapsedTime() {
-        return mConnectElapsedTime;
-    }
-
-    public void setConnectElapsedTime(long connectElapsedTime) {
-        mConnectElapsedTime = connectElapsedTime;
-    }
-
-    /**
-     * @return The direction of the call (incoming/outgoing).
-     */
-    public @Call.Details.CallDirection int getCallDirection() {
-        return mCallDirection;
-    }
-
-    /**
-     * Sets the direction of the call.
-     * @param callDirection Whether the call is incoming or outgoing.
-     */
-    public void setCallDirection(@Call.Details.CallDirection int callDirection) {
-        mCallDirection = callDirection;
-    }
-
-    /**
-     * Attempts to build a tel: style URI from a conference participant.
-     * Conference event package data contains SIP URIs, so we try to extract the phone number and
-     * format into a typical tel: style URI.
-     *
-     * @param address The conference participant's address.
-     * @param countryIso The country ISO of the current subscription; used when formatting the
-     *                   participant phone number to E.164 format.
-     * @return The participant's address URI.
-     * @hide
-     */
-    @VisibleForTesting
-    public static Uri getParticipantAddress(Uri address, String countryIso) {
-        if (address == null) {
-            return address;
-        }
-        // Even if address is already in tel: format, still parse it and rebuild.
-        // This is to recognize tel URIs such as:
-        // tel:6505551212;phone-context=ims.mnc012.mcc034.3gppnetwork.org
-
-        // Conference event package participants are identified using SIP URIs (see RFC3261).
-        // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
-        // Per RFC3261, the "user" can be a telephone number.
-        // For example: sip:1650555121;phone-context=blah.com@host.com
-        // In this case, the phone number is in the user field of the URI, and the parameters can be
-        // ignored.
-        //
-        // A SIP URI can also specify a phone number in a format similar to:
-        // sip:+1-212-555-1212@something.com;user=phone
-        // In this case, the phone number is again in user field and the parameters can be ignored.
-        // We can get the user field in these instances by splitting the string on the @, ;, or :
-        // and looking at the first found item.
-        String number = address.getSchemeSpecificPart();
-        if (TextUtils.isEmpty(number)) {
-            return address;
-        }
-
-        String numberParts[] = number.split("[@;:]");
-        if (numberParts.length == 0) {
-            return address;
-        }
-        number = numberParts[0];
-
-        // Attempt to format the number in E.164 format and use that as part of the TEL URI.
-        // RFC2806 recommends to format telephone numbers using E.164 since it is independent of
-        // how the dialing of said numbers takes place.
-        // If conversion to E.164 fails, the returned value is null.  In that case, fallback to the
-        // number which was in the CEP data.
-        String formattedNumber = null;
-        if (!TextUtils.isEmpty(countryIso)) {
-            formattedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
-        }
-
-        return Uri.fromParts(PhoneAccount.SCHEME_TEL,
-                formattedNumber != null ? formattedNumber : number, null);
-    }
-}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 20abe77..4c22ba9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.Notification;
 import android.bluetooth.BluetoothDevice;
@@ -274,6 +275,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
 
     /**
@@ -311,6 +313,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
 
     /**
@@ -357,6 +360,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 1<<0;
 
     /**
@@ -367,6 +371,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROPERTY_GENERIC_CONFERENCE = 1<<1;
 
     /**
@@ -418,6 +423,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROPERTY_IS_DOWNGRADED_CONFERENCE = 1<<6;
 
     /**
@@ -436,7 +442,10 @@
 
     /**
      * Set by the framework to indicate that a connection is using assisted dialing.
-     * @hide
+     * <p>
+     * This is used for outgoing calls.
+     *
+     * @see TelecomManager#EXTRA_USE_ASSISTED_DIALING
      */
     public static final int PROPERTY_ASSISTED_DIALING_USED = 1 << 9;
 
@@ -458,6 +467,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final int PROPERTY_REMOTELY_HOSTED = 1 << 11;
 
     //**********************************************************************************************
@@ -516,6 +526,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final String EXTRA_DISABLE_ADD_CALL =
             "android.telecom.extra.DISABLE_ADD_CALL";
 
@@ -1807,6 +1818,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final @Nullable String getTelecomCallId() {
         return mTelecomCallId;
     }
@@ -1923,6 +1935,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final long getConnectTimeMillis() {
         return mConnectTimeMillis;
     }
@@ -1942,32 +1955,12 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final long getConnectElapsedTimeMillis() {
         return mConnectElapsedTimeMillis;
     }
 
     /**
-     * Returns RIL voice radio technology used for current connection.
-     * <p>
-     * Used by the Telephony {@link ConnectionService}.
-     *
-     * @return the RIL voice radio technology used for current connection,
-     *         see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
-     *
-     * @hide
-     */
-    @SystemApi
-    public final @RilRadioTechnology int getCallRadioTech() {
-        int voiceNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
-        Bundle extras = getExtras();
-        if (extras != null) {
-            voiceNetworkType = extras.getInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN);
-        }
-        return ServiceState.networkTypeToRilRadioTechnology(voiceNetworkType);
-    }
-
-    /**
      * @return The status hints for this connection.
      */
     public final StatusHints getStatusHints() {
@@ -2045,6 +2038,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setTelecomCallId(@NonNull String callId) {
         mTelecomCallId = callId;
     }
@@ -2391,6 +2385,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final void setConnectTimeMillis(long connectTimeMillis) {
         mConnectTimeMillis = connectTimeMillis;
     }
@@ -2406,39 +2401,12 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final void setConnectionStartElapsedRealTime(long connectElapsedTimeMillis) {
         mConnectElapsedTimeMillis = connectElapsedTimeMillis;
     }
 
     /**
-     * Sets RIL voice radio technology used for current connection.
-     * <p>
-     * This property is set by the Telephony {@link ConnectionService}.
-     *
-     * @param vrat the RIL Voice Radio Technology used for current connection,
-     *             see {@code RIL_RADIO_TECHNOLOGY_*} in {@link android.telephony.ServiceState}.
-     *
-     * @hide
-     */
-    @SystemApi
-    public final void setCallRadioTech(@RilRadioTechnology int vrat) {
-        Bundle extras = getExtras();
-        if (extras == null) {
-            extras = new Bundle();
-        }
-        extras.putInt(TelecomManager.EXTRA_CALL_NETWORK_TYPE,
-                ServiceState.rilRadioTechnologyToNetworkType(vrat));
-        putExtras(extras);
-        // Propagates the call radio technology to its parent {@link android.telecom.Conference}
-        // This action only covers non-IMS CS conference calls.
-        // For IMS PS call conference call, it can be updated via its host connection
-        // {@link #Listener.onExtrasChanged} event.
-        if (getConference() != null) {
-            getConference().setCallRadioTech(vrat);
-        }
-    }
-
-    /**
      * Sets the label and icon status to display in the in-call UI.
      *
      * @param statusHints The status label and icon to set.
@@ -2502,6 +2470,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public final void resetConnectionTime() {
         for (Listener l : mListeners) {
             l.onConnectionTimeReset(this);
@@ -3246,6 +3215,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
         if (mPhoneAccountHandle != phoneAccountHandle) {
             mPhoneAccountHandle = phoneAccountHandle;
@@ -3264,6 +3234,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public @Nullable PhoneAccountHandle getPhoneAccountHandle() {
         return mPhoneAccountHandle;
     }
@@ -3329,6 +3300,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setCallDirection(@Call.Details.CallDirection int callDirection) {
         mCallDirection = callDirection;
     }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 0abd9fc..812b805 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -16,7 +16,11 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
 import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -2106,15 +2110,21 @@
 
     /**
      * Adds a connection created by the {@link ConnectionService} and informs telecom of the new
-     * connection.
+     * connection, as well as adding that connection to the specified conference.
+     * <p>
+     * Note: This API is intended ONLY for use by the Telephony stack to provide an easy way to add
+     * IMS conference participants to be added to a conference in a single step; this helps ensure
+     * UI updates happen atomically, rather than adding the connection and then adding it to
+     * the conference in another step.
      *
      * @param phoneAccountHandle The phone account handle for the connection.
      * @param connection The connection to add.
      * @param conference The parent conference of the new connection.
      * @hide
      */
-    public final void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
-            Connection connection, Conference conference) {
+    @SystemApi
+    public final void addExistingConnection(@NonNull PhoneAccountHandle phoneAccountHandle,
+            @NonNull Connection connection, @NonNull Conference conference) {
 
         String id = addExistingConnectionInternal(phoneAccountHandle, connection);
         if (id != null) {
diff --git a/telecomm/java/android/telecom/Logging/Session.java b/telecomm/java/android/telecom/Logging/Session.java
index 95a47e1..d82e93f 100644
--- a/telecomm/java/android/telecom/Logging/Session.java
+++ b/telecomm/java/android/telecom/Logging/Session.java
@@ -237,7 +237,10 @@
     // keep track of calls and bail if we hit the recursion limit
     private String getFullSessionId(int parentCount) {
         if (parentCount >= SESSION_RECURSION_LIMIT) {
-            Log.w(LOG_TAG, "getFullSessionId: Hit recursion limit!");
+            // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
+            // try to add session information to this logging statement, which will cause it to hit
+            // this condition again and so on...
+            android.util.Slog.w(LOG_TAG, "getFullSessionId: Hit recursion limit!");
             return TRUNCATE_STRING + mSessionId;
         }
         // Cache mParentSession locally to prevent a concurrency problem where
@@ -265,7 +268,11 @@
         Session topNode = this;
         while (topNode.getParentSession() != null) {
             if (currParentCount >= SESSION_RECURSION_LIMIT) {
-                Log.w(LOG_TAG, "getRootSession: Hit recursion limit from " + callingMethod);
+                // Don't use Telecom's Log.w here or it will cause infinite recursion because it
+                // will try to add session information to this logging statement, which will cause
+                // it to hit this condition again and so on...
+                android.util.Slog.w(LOG_TAG, "getRootSession: Hit recursion limit from "
+                        + callingMethod);
                 break;
             }
             topNode = topNode.getParentSession();
@@ -289,7 +296,10 @@
     private void printSessionTree(int tabI, StringBuilder sb, int currChildCount) {
         // Prevent infinite recursion.
         if (currChildCount >= SESSION_RECURSION_LIMIT) {
-            Log.w(LOG_TAG, "printSessionTree: Hit recursion limit!");
+            // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
+            // try to add session information to this logging statement, which will cause it to hit
+            // this condition again and so on...
+            android.util.Slog.w(LOG_TAG, "printSessionTree: Hit recursion limit!");
             sb.append(TRUNCATE_STRING);
             return;
         }
@@ -315,7 +325,10 @@
     private synchronized void getFullMethodPath(StringBuilder sb, boolean truncatePath,
             int parentCount) {
         if (parentCount >= SESSION_RECURSION_LIMIT) {
-            Log.w(LOG_TAG, "getFullMethodPath: Hit recursion limit!");
+            // Don't use Telecom's Log.w here or it will cause infinite recursion because it will
+            // try to add session information to this logging statement, which will cause it to hit
+            // this condition again and so on...
+            android.util.Slog.w(LOG_TAG, "getFullMethodPath: Hit recursion limit!");
             sb.append(TRUNCATE_STRING);
             return;
         }
diff --git a/telecomm/java/android/telecom/Logging/SessionManager.java b/telecomm/java/android/telecom/Logging/SessionManager.java
index 49c3a72..ac30058 100644
--- a/telecomm/java/android/telecom/Logging/SessionManager.java
+++ b/telecomm/java/android/telecom/Logging/SessionManager.java
@@ -202,7 +202,18 @@
         return createSubsession(false);
     }
 
-    private synchronized Session createSubsession(boolean isStartedFromActiveSession) {
+    /**
+     * Creates a new subsession based on an existing session. Will not be started until
+     * {@link #continueSession(Session, String)} or {@link #cancelSubsession(Session)} is called.
+     * <p>
+     * Only public for testing!
+     * @param isStartedFromActiveSession true if this subsession is being created for a task on the
+     *     same thread, false if it is being created for a related task on another thread.
+     * @return a new {@link Session}, call {@link #continueSession(Session, String)} to continue the
+     * session and {@link #endSession()} when done with this subsession.
+     */
+    @VisibleForTesting
+    public synchronized Session createSubsession(boolean isStartedFromActiveSession) {
         int threadId = getCallingThreadId();
         Session threadSession = mSessionMapper.get(threadId);
         if (threadSession == null) {
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/Phone.java b/telecomm/java/android/telecom/Phone.java
index 2ecdb30..61a639a1 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -152,13 +152,20 @@
             return;
         }
 
-        Call call = new Call(this, parcelableCall.getId(), mInCallAdapter,
-                parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
-        mCallByTelecomCallId.put(parcelableCall.getId(), call);
-        mCalls.add(call);
-        checkCallTree(parcelableCall);
-        call.internalUpdate(parcelableCall, mCallByTelecomCallId);
-        fireCallAdded(call);
+        Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+        if (call == null) {
+            call = new Call(this, parcelableCall.getId(), mInCallAdapter,
+                    parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
+            mCallByTelecomCallId.put(parcelableCall.getId(), call);
+            mCalls.add(call);
+            checkCallTree(parcelableCall);
+            call.internalUpdate(parcelableCall, mCallByTelecomCallId);
+            fireCallAdded(call);
+        } else {
+            Log.w(this, "Call %s added, but it was already present", call.internalGetCallId());
+            checkCallTree(parcelableCall);
+            call.internalUpdate(parcelableCall, mCallByTelecomCallId);
+        }
     }
 
     final void internalRemoveCall(Call call) {
@@ -190,7 +197,11 @@
         } else {
             // This call may have come out of audio processing. Try adding it if our target sdk
             // version is low enough.
-            if (mTargetSdkVersion < SDK_VERSION_R) {
+            // The only two allowable states coming out of audio processing are ACTIVE and
+            // SIMULATED_RINGING.
+            if (mTargetSdkVersion < SDK_VERSION_R && (parcelableCall.getState() == Call.STATE_ACTIVE
+                    || parcelableCall.getState() == Call.STATE_SIMULATED_RINGING)) {
+                Log.i(this, "adding call during update for sdk compatibility");
                 internalAddCall(parcelableCall);
             }
         }
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 1b783b7..bb858cb 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -16,7 +16,9 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
@@ -592,12 +594,17 @@
          * only be one {@link PhoneAccount} with a non-empty group number registered to Telecom at a
          * time. By default, there is no group Id for a {@link PhoneAccount} (an empty String). Only
          * grouped {@link PhoneAccount}s with the same {@link ConnectionService} can be replaced.
+         * <p>
+         * Note: This is an API specific to the Telephony stack.
+         *
          * @param groupId The group Id of the {@link PhoneAccount} that will replace any other
          * registered {@link PhoneAccount} in Telecom with the same Group Id.
          * @return The builder
          * @hide
          */
-        public Builder setGroupId(String groupId) {
+        @SystemApi
+        @TestApi
+        public @NonNull Builder setGroupId(@NonNull String groupId) {
             if (groupId != null) {
                 mGroupId = groupId;
             } else {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 625cd72..4016943 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -14,6 +14,8 @@
 
 package android.telecom;
 
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
 import android.Manifest;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -697,7 +699,17 @@
     /**
      * The boolean indicated by this extra controls whether or not a call is eligible to undergo
      * assisted dialing. This extra is stored under {@link #EXTRA_OUTGOING_CALL_EXTRAS}.
-     * @hide
+     * <p>
+     * The call initiator can use this extra to indicate that a call used assisted dialing to help
+     * place the call.  This is most commonly used by a Dialer app which provides the ability to
+     * automatically add dialing prefixes when placing international calls.
+     * <p>
+     * Setting this extra on the outgoing call extras will cause the
+     * {@link Connection#PROPERTY_ASSISTED_DIALING_USED} property and
+     * {@link Call.Details#PROPERTY_ASSISTED_DIALING_USED} property to be set on the
+     * {@link Connection}/{@link Call} in question.  When the call is logged to the call log, the
+     * {@link android.provider.CallLog.Calls#FEATURES_ASSISTED_DIALING_USED} call feature is set to
+     * indicate that assisted dialing was used for the call.
      */
     public static final String EXTRA_USE_ASSISTED_DIALING =
             "android.telecom.extra.USE_ASSISTED_DIALING";
@@ -739,6 +751,14 @@
      */
     public static final int PRESENTATION_PAYPHONE = 4;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(
+            prefix = { "PRESENTATION_" },
+            value = {PRESENTATION_ALLOWED, PRESENTATION_RESTRICTED, PRESENTATION_UNKNOWN,
+            PRESENTATION_PAYPHONE})
+    public @interface Presentation {}
+
     private static final String TAG = "TelecomManager";
 
     private final Context mContext;
@@ -884,9 +904,8 @@
      *                       queried for.
      * @return The phone account handle of the current sim call manager.
      * @see SubscriptionManager#getActiveSubscriptionInfoList()
-     * @hide
      */
-    public PhoneAccountHandle getSimCallManagerForSubscription(int subscriptionId) {
+    public @Nullable PhoneAccountHandle getSimCallManagerForSubscription(int subscriptionId) {
         try {
             if (isServiceConnected()) {
                 return getTelecomService().getSimCallManager(subscriptionId);
@@ -948,7 +967,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE
     })
     public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme) {
@@ -1235,6 +1254,28 @@
     }
 
     /**
+     * Used to determine the currently selected default dialer package for a specific user.
+     *
+     * @param userId the user id to query the default dialer package for.
+     * @return package name for the default dialer package or null if no package has been
+     *         selected as the default dialer.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
+    public @Nullable String getDefaultDialerPackage(int userId) {
+        try {
+            if (isServiceConnected()) {
+                return getTelecomService().getDefaultDialerPackageForUser(userId);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException attempting to get the default dialer package name.", e);
+        }
+        return null;
+    }
+
+    /**
      * Used to set the default dialer package.
      *
      * @param packageName to set the default dialer to, or {@code null} if the system provided
@@ -1433,7 +1474,7 @@
      */
     @SystemApi
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE
     })
     public boolean isRinging() {
@@ -1563,7 +1604,7 @@
      * Returns whether TTY is supported on this device.
      */
     @RequiresPermission(anyOf = {
-            android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            READ_PRIVILEGED_PHONE_STATE,
             android.Manifest.permission.READ_PHONE_STATE
     })
     public boolean isTtySupported() {
@@ -1589,7 +1630,7 @@
      */
     @SystemApi
     @TestApi
-    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @RequiresPermission(READ_PRIVILEGED_PHONE_STATE)
     public @TtyMode int getCurrentTtyMode() {
         try {
             if (isServiceConnected()) {
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/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 2411988..de3a816 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -146,6 +146,11 @@
     String getDefaultDialerPackage();
 
     /**
+     * @see TelecomServiceImpl#getDefaultDialerPackage
+     */
+    String getDefaultDialerPackageForUser(int userId);
+
+    /**
      * @see TelecomServiceImpl#getSystemDialerPackage
      */
     String getSystemDialerPackage();
diff --git a/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
new file mode 100644
index 0000000..922af12
--- /dev/null
+++ b/telephony/common/com/android/internal/telephony/PackageChangeReceiver.java
@@ -0,0 +1,167 @@
+/*
+ * 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+
+import com.android.internal.os.BackgroundThread;
+
+/**
+ * Helper class for monitoring the state of packages: adding, removing,
+ * updating, and disappearing and reappearing on the SD card.
+ */
+public abstract class PackageChangeReceiver extends BroadcastReceiver {
+    static final IntentFilter sPackageIntentFilter = new IntentFilter();
+    static {
+        sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        sPackageIntentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
+        sPackageIntentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+        sPackageIntentFilter.addDataScheme("package");
+    }
+    Context mRegisteredContext;
+
+    /**
+     * To register the intents that needed for monitoring the state of packages
+     */
+    public void register(@NonNull Context context, @Nullable Looper thread,
+            @Nullable UserHandle user) {
+        if (mRegisteredContext != null) {
+            throw new IllegalStateException("Already registered");
+        }
+        Handler handler = (thread == null) ? BackgroundThread.getHandler() : new Handler(thread);
+        mRegisteredContext = context;
+        if (handler != null) {
+            if (user != null) {
+                context.registerReceiverAsUser(this, user, sPackageIntentFilter, null, handler);
+            } else {
+                context.registerReceiver(this, sPackageIntentFilter,
+                        null, handler);
+            }
+        } else {
+            throw new NullPointerException();
+        }
+    }
+
+    /**
+     * To unregister the intents for monitoring the state of packages
+     */
+    public void unregister() {
+        if (mRegisteredContext == null) {
+            throw new IllegalStateException("Not registered");
+        }
+        mRegisteredContext.unregisterReceiver(this);
+        mRegisteredContext = null;
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED
+     */
+    public void onPackageAdded(@Nullable String packageName) {
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_PACKAGE_REMOVED
+     */
+    public void onPackageRemoved(@Nullable String packageName) {
+    }
+
+    /**
+     * This method is invoked when Intent.EXTRA_REPLACING as extra field is true
+     */
+    public void onPackageUpdateFinished(@Nullable String packageName) {
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_PACKAGE_CHANGED or
+     * Intent.EXTRA_REPLACING as extra field is true
+     */
+    public void onPackageModified(@Nullable String packageName) {
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_QUERY_PACKAGE_RESTART and
+     * Intent.ACTION_PACKAGE_RESTARTED
+     */
+    public void onHandleForceStop(@Nullable String[] packages, boolean doit) {
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_PACKAGE_REMOVED
+     */
+    public void onPackageDisappeared() {
+    }
+
+    /**
+     * This method is invoked when receive the Intent.ACTION_PACKAGE_ADDED
+     */
+    public void onPackageAppeared() {
+    }
+
+    @Override
+    public void onReceive(@Nullable Context context, @Nullable Intent intent) {
+        String action = intent.getAction();
+
+        if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
+            String pkg = getPackageName(intent);
+            if (pkg != null) {
+                if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    onPackageUpdateFinished(pkg);
+                    onPackageModified(pkg);
+                } else {
+                    onPackageAdded(pkg);
+                }
+                onPackageAppeared();
+            }
+        } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+            String pkg = getPackageName(intent);
+            if (pkg != null) {
+                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                    onPackageRemoved(pkg);
+                }
+                onPackageDisappeared();
+            }
+        } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
+            String pkg = getPackageName(intent);
+            if (pkg != null) {
+                onPackageModified(pkg);
+            }
+        } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
+            String[] disappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
+            onHandleForceStop(disappearingPackages, false);
+        } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+            String[] disappearingPackages = new String[] {getPackageName(intent)};
+            onHandleForceStop(disappearingPackages, true);
+        }
+    }
+
+    String getPackageName(Intent intent) {
+        Uri uri = intent.getData();
+        String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
+        return pkg;
+    }
+}
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index f4eae8e..70ce1bf 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -39,11 +39,11 @@
 import android.os.UserHandle;
 import android.provider.Telephony;
 import android.provider.Telephony.Sms.Intents;
+import android.telephony.PackageChangeReceiver;
 import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
-import com.android.internal.content.PackageMonitor;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
@@ -777,7 +777,7 @@
      * Tracks package changes and ensures that the default SMS app is always configured to be the
      * preferred activity for SENDTO sms/mms intents.
      */
-    private static final class SmsPackageMonitor extends PackageMonitor {
+    private static final class SmsPackageMonitor extends PackageChangeReceiver {
         final Context mContext;
 
         public SmsPackageMonitor(Context context) {
@@ -786,12 +786,12 @@
         }
 
         @Override
-        public void onPackageDisappeared(String packageName, int reason) {
+        public void onPackageDisappeared() {
             onPackageChanged();
         }
 
         @Override
-        public void onPackageAppeared(String packageName, int reason) {
+        public void onPackageAppeared() {
             onPackageChanged();
         }
 
@@ -824,7 +824,7 @@
 
     public static void initSmsPackageMonitor(Context context) {
         sSmsPackageMonitor = new SmsPackageMonitor(context);
-        sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
+        sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL);
     }
 
     @UnsupportedAppUsage
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index dc95f16..9577680 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1126,8 +1126,9 @@
              * values:</p>
              *
              * <ul>
-             *   <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
-             *   data, including ETWS or CMAS warning notification info if present.</li>
+             *   <li><em>"message"</em> - An {@link android.telephony.SmsCbMessage} object
+             *   containing the broadcast message data, including ETWS or CMAS warning notification
+             *   info if present.</li>
              * </ul>
              *
              * <p>The extra values can be extracted using
@@ -1138,11 +1139,12 @@
              *
              * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} to
              * receive.</p>
-             * @removed
+             * @hide
              */
             @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-            public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION =
-                    "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
+            @SystemApi
+            public static final String ACTION_SMS_EMERGENCY_CB_RECEIVED =
+                    "android.provider.action.SMS_EMERGENCY_CB_RECEIVED";
 
             /**
              * Broadcast Action: A new CDMA SMS has been received containing Service Category
@@ -1363,22 +1365,76 @@
      * Base column for the table that contain Carrier Public key.
      * @hide
      */
+    @SystemApi
     public interface CarrierColumns extends BaseColumns {
 
+        /**
+         * Mobile Country Code (MCC).
+         * <P> Type: TEXT </P>
+         */
         public static final String MCC = "mcc";
+
+        /**
+         * Mobile Network Code (MNC).
+         * <P> Type: TEXT </P>
+         */
         public static final String MNC = "mnc";
+
+        /**
+         * KeyType whether the key is being used for WLAN or ePDG.
+         * <P> Type: INTEGER </P>
+         */
         public static final String KEY_TYPE = "key_type";
+
+        /**
+         * MVNO type:
+         * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
+         * <P> Type: TEXT </P>
+         */
         public static final String MVNO_TYPE = "mvno_type";
+
+        /**
+         * MVNO data.
+         * Use the following examples.
+         * <ul>
+         *     <li>SPN: A MOBILE, BEN NL, ...</li>
+         *     <li>IMSI: 302720x94, 2060188, ...</li>
+         *     <li>GID: 4E, 33, ...</li>
+         * </ul>
+         * <P> Type: TEXT </P>
+         */
         public static final String MVNO_MATCH_DATA = "mvno_match_data";
+
+        /**
+         * The carrier public key that is used for the IMSI encryption.
+         * <P> Type: TEXT </P>
+         */
         public static final String PUBLIC_KEY = "public_key";
+
+        /**
+         * The key identifier Attribute value pair that helps a server locate
+         * the private key to decrypt the permanent identity.
+         * <P> Type: TEXT </P>
+         */
         public static final String KEY_IDENTIFIER = "key_identifier";
+
+        /**
+         * Date-Time in UTC when the key will expire.
+         * <P> Type: INTEGER (long) </P>
+         */
         public static final String EXPIRATION_TIME = "expiration_time";
+
+        /**
+         * Timestamp when this table was last modified, in milliseconds since
+         * January 1, 1970 00:00:00.0 UTC.
+         * <P> Type: INTEGER (long) </P>
+         */
         public static final String LAST_MODIFIED = "last_modified";
 
         /**
          * The {@code content://} style URL for this table.
-         * @hide
          */
+        @NonNull
         public static final Uri CONTENT_URI = Uri.parse("content://carrier_information/carrier");
     }
 
@@ -4691,7 +4747,16 @@
          * Contains mappings between matching rules with carrier id for all carriers.
          * @hide
          */
+        @SystemApi
         public static final class All implements BaseColumns {
+
+            /**
+             * Not instantiable.
+             * @hide
+             */
+            private All() {
+            }
+
             /**
              * Numeric operator ID (as String). {@code MCC + MNC}
              * <P>Type: TEXT </P>
@@ -4749,6 +4814,7 @@
             /**
              * The {@code content://} URI for this table.
              */
+            @NonNull
             public static final Uri CONTENT_URI = Uri.parse("content://carrier_id/all");
         }
     }
diff --git a/telephony/java/android/telephony/CbGeoUtils.java b/telephony/java/android/telephony/CbGeoUtils.java
index f4ce6e7..ce5e3f3 100644
--- a/telephony/java/android/telephony/CbGeoUtils.java
+++ b/telephony/java/android/telephony/CbGeoUtils.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.os.Build;
 import android.text.TextUtils;
 
 import java.util.ArrayList;
@@ -257,6 +258,15 @@
                 return new Point(x - p.x, y - p.y);
             }
         }
+
+        @Override
+        public String toString() {
+            String str = "Polygon: ";
+            if (Build.IS_DEBUGGABLE) {
+                str += mVertices;
+            }
+            return str;
+        }
     }
 
     /**
@@ -284,6 +294,16 @@
         public boolean contains(LatLng p) {
             return mCenter.distance(p) <= mRadiusMeter;
         }
+
+        @Override
+        public String toString() {
+            String str = "Circle: ";
+            if (Build.IS_DEBUGGABLE) {
+                str += mCenter + ", radius = " + mRadiusMeter;
+            }
+
+            return str;
+        }
     }
 
     /**
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 407ced7..270eafe 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -203,9 +203,12 @@
     }
 
     /**
+     * Get whether network has configured carrier aggregation or not.
+     *
      * @return {@code true} if using carrier aggregation.
      * @hide
      */
+    @SystemApi
     public boolean isUsingCarrierAggregation() {
         return mIsUsingCarrierAggregation;
     }
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 56b7236..fc717e7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -323,9 +323,12 @@
     public @Domain int getDomain() { return mDomain; }
 
     /**
+     * Get the 5G NR connection state.
+     *
      * @return the 5G NR connection state.
      * @hide
      */
+    @SystemApi
     public @NRState int getNrState() {
         return mNrState;
     }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4a1bc1f..67afa7d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
-
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -31,9 +29,9 @@
 import android.location.CountryDetector;
 import android.net.Uri;
 import android.os.PersistableBundle;
-import android.os.SystemProperties;
 import android.provider.Contacts;
 import android.provider.ContactsContract;
+import android.sysprop.TelephonyProperties;
 import android.telecom.PhoneAccount;
 import android.text.Editable;
 import android.text.Spannable;
@@ -2659,7 +2657,7 @@
             ps = NANP_IDP_STRING;
         } else {
             // in case, there is no IDD is found, we shouldn't convert it.
-            ps = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, PLUS_SIGN_STRING);
+            ps = TelephonyProperties.operator_idp_string().orElse(PLUS_SIGN_STRING);
         }
         return ps;
     }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f503348..9ace86c 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1384,9 +1384,12 @@
     }
 
     /**
+     * Get the 5G NR frequency range the device is currently registered.
+     *
      * @return the frequency range of 5G NR.
      * @hide
      */
+    @SystemApi
     public @FrequencyRange int getNrFrequencyRange() {
         return mNrFrequencyRange;
     }
@@ -1464,44 +1467,44 @@
     /** @hide */
     public static int rilRadioTechnologyToNetworkType(@RilRadioTechnology int rat) {
         switch(rat) {
-            case ServiceState.RIL_RADIO_TECHNOLOGY_GPRS:
+            case RIL_RADIO_TECHNOLOGY_GPRS:
                 return TelephonyManager.NETWORK_TYPE_GPRS;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_EDGE:
+            case RIL_RADIO_TECHNOLOGY_EDGE:
                 return TelephonyManager.NETWORK_TYPE_EDGE;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_UMTS:
+            case RIL_RADIO_TECHNOLOGY_UMTS:
                 return TelephonyManager.NETWORK_TYPE_UMTS;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA:
+            case RIL_RADIO_TECHNOLOGY_HSDPA:
                 return TelephonyManager.NETWORK_TYPE_HSDPA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA:
+            case RIL_RADIO_TECHNOLOGY_HSUPA:
                 return TelephonyManager.NETWORK_TYPE_HSUPA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_HSPA:
+            case RIL_RADIO_TECHNOLOGY_HSPA:
                 return TelephonyManager.NETWORK_TYPE_HSPA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_IS95A:
-            case ServiceState.RIL_RADIO_TECHNOLOGY_IS95B:
+            case RIL_RADIO_TECHNOLOGY_IS95A:
+            case RIL_RADIO_TECHNOLOGY_IS95B:
                 return TelephonyManager.NETWORK_TYPE_CDMA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT:
+            case RIL_RADIO_TECHNOLOGY_1xRTT:
                 return TelephonyManager.NETWORK_TYPE_1xRTT;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0:
+            case RIL_RADIO_TECHNOLOGY_EVDO_0:
                 return TelephonyManager.NETWORK_TYPE_EVDO_0;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A:
+            case RIL_RADIO_TECHNOLOGY_EVDO_A:
                 return TelephonyManager.NETWORK_TYPE_EVDO_A;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B:
+            case RIL_RADIO_TECHNOLOGY_EVDO_B:
                 return TelephonyManager.NETWORK_TYPE_EVDO_B;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD:
+            case RIL_RADIO_TECHNOLOGY_EHRPD:
                 return TelephonyManager.NETWORK_TYPE_EHRPD;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_LTE:
+            case RIL_RADIO_TECHNOLOGY_LTE:
                 return TelephonyManager.NETWORK_TYPE_LTE;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP:
+            case RIL_RADIO_TECHNOLOGY_HSPAP:
                 return TelephonyManager.NETWORK_TYPE_HSPAP;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
+            case RIL_RADIO_TECHNOLOGY_GSM:
                 return TelephonyManager.NETWORK_TYPE_GSM;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA:
+            case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
                 return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
+            case RIL_RADIO_TECHNOLOGY_IWLAN:
                 return TelephonyManager.NETWORK_TYPE_IWLAN;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA:
+            case RIL_RADIO_TECHNOLOGY_LTE_CA:
                 return TelephonyManager.NETWORK_TYPE_LTE_CA;
-            case ServiceState.RIL_RADIO_TECHNOLOGY_NR:
+            case RIL_RADIO_TECHNOLOGY_NR:
                 return TelephonyManager.NETWORK_TYPE_NR;
             default:
                 return TelephonyManager.NETWORK_TYPE_UNKNOWN;
@@ -1546,45 +1549,45 @@
     public static int networkTypeToRilRadioTechnology(int networkType) {
         switch(networkType) {
             case TelephonyManager.NETWORK_TYPE_GPRS:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_GPRS;
+                return RIL_RADIO_TECHNOLOGY_GPRS;
             case TelephonyManager.NETWORK_TYPE_EDGE:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_EDGE;
+                return RIL_RADIO_TECHNOLOGY_EDGE;
             case TelephonyManager.NETWORK_TYPE_UMTS:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_UMTS;
+                return RIL_RADIO_TECHNOLOGY_UMTS;
             case TelephonyManager.NETWORK_TYPE_HSDPA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA;
+                return RIL_RADIO_TECHNOLOGY_HSDPA;
             case TelephonyManager.NETWORK_TYPE_HSUPA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA;
+                return RIL_RADIO_TECHNOLOGY_HSUPA;
             case TelephonyManager.NETWORK_TYPE_HSPA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+                return RIL_RADIO_TECHNOLOGY_HSPA;
             case TelephonyManager.NETWORK_TYPE_CDMA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_IS95A;
+                return RIL_RADIO_TECHNOLOGY_IS95A;
             case TelephonyManager.NETWORK_TYPE_1xRTT:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
+                return RIL_RADIO_TECHNOLOGY_1xRTT;
             case TelephonyManager.NETWORK_TYPE_EVDO_0:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0;
+                return RIL_RADIO_TECHNOLOGY_EVDO_0;
             case TelephonyManager.NETWORK_TYPE_EVDO_A:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A;
+                return RIL_RADIO_TECHNOLOGY_EVDO_A;
             case TelephonyManager.NETWORK_TYPE_EVDO_B:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B;
+                return RIL_RADIO_TECHNOLOGY_EVDO_B;
             case TelephonyManager.NETWORK_TYPE_EHRPD:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD;
+                return RIL_RADIO_TECHNOLOGY_EHRPD;
             case TelephonyManager.NETWORK_TYPE_LTE:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+                return RIL_RADIO_TECHNOLOGY_LTE;
             case TelephonyManager.NETWORK_TYPE_HSPAP:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP;
+                return RIL_RADIO_TECHNOLOGY_HSPAP;
             case TelephonyManager.NETWORK_TYPE_GSM:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_GSM;
+                return RIL_RADIO_TECHNOLOGY_GSM;
             case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA;
+                return RIL_RADIO_TECHNOLOGY_TD_SCDMA;
             case TelephonyManager.NETWORK_TYPE_IWLAN:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+                return RIL_RADIO_TECHNOLOGY_IWLAN;
             case TelephonyManager.NETWORK_TYPE_LTE_CA:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA;
+                return RIL_RADIO_TECHNOLOGY_LTE_CA;
             case TelephonyManager.NETWORK_TYPE_NR:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+                return RIL_RADIO_TECHNOLOGY_NR;
             default:
-                return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+                return RIL_RADIO_TECHNOLOGY_UNKNOWN;
         }
     }
 
@@ -1950,8 +1953,11 @@
     /**
      * The current registered raw data network operator name in long alphanumeric format.
      *
+     * @return long raw name of operator, null if unregistered or unknown
      * @hide
      */
+    @Nullable
+    @SystemApi
     public String getOperatorAlphaLongRaw() {
         return mOperatorAlphaLongRaw;
     }
@@ -1966,8 +1972,11 @@
     /**
      * The current registered raw data network operator name in short alphanumeric format.
      *
+     * @return short raw name of operator, null if unregistered or unknown
      * @hide
      */
+    @Nullable
+    @SystemApi
     public String getOperatorAlphaShortRaw() {
         return mOperatorAlphaShortRaw;
     }
diff --git a/telephony/java/android/telephony/SmsCbLocation.java b/telephony/java/android/telephony/SmsCbLocation.java
index d8a4754..663e8e2 100644
--- a/telephony/java/android/telephony/SmsCbLocation.java
+++ b/telephony/java/android/telephony/SmsCbLocation.java
@@ -65,6 +65,10 @@
     /**
      * Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so
      * the same object can be reused for multiple broadcasts.
+     *
+     * @param plmn the MCC/MNC of the network
+     * @param lac the GSM location area code, or UMTS service area code
+     * @param cid the GSM or UMTS cell ID
      */
     public SmsCbLocation(@NonNull String plmn, int lac, int cid) {
         mPlmn = plmn;
diff --git a/telephony/java/android/telephony/SmsCbMessage.java b/telephony/java/android/telephony/SmsCbMessage.java
index 3e044e5..737ead1 100644
--- a/telephony/java/android/telephony/SmsCbMessage.java
+++ b/telephony/java/android/telephony/SmsCbMessage.java
@@ -138,8 +138,8 @@
     public @interface MessagePriority {}
 
     /**
-     * ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
-     * @hide
+     * Integer indicating that the maximum wait time is not set.
+     * Based on ATIS-0700041 Section 5.2.8 WAC Geo-Fencing Maximum Wait Time Table 12.
      */
     public static final int MAXIMUM_WAIT_TIME_NOT_SET = 255;
 
@@ -209,6 +209,7 @@
 
     /**
      * Create a new SmsCbMessage with the specified data.
+     * @hide
      */
     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
             @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
@@ -221,14 +222,14 @@
     }
 
     /**
-     * Create a new {@link SmsCbMessage} with the warning area coordinates information.
-     * @hide
+     * Create a new {@link SmsCbMessage} with the specified data, including warning area
+     * coordinates information.
      */
     public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
-            SmsCbLocation location, int serviceCategory, String language, String body,
-            int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo,
-            int maximumWaitTimeSec, List<Geometry> geometries, long receivedTimeMillis,
-            int slotIndex) {
+            @NonNull SmsCbLocation location, int serviceCategory, @Nullable String language,
+            @Nullable String body, int priority, @Nullable SmsCbEtwsInfo etwsWarningInfo,
+            @Nullable SmsCbCmasInfo cmasWarningInfo, int maximumWaitTimeSec,
+            @Nullable List<Geometry> geometries, long receivedTimeMillis, int slotIndex) {
         mMessageFormat = messageFormat;
         mGeographicalScope = geographicalScope;
         mSerialNumber = serialNumber;
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index dfcfed7..1770671 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -3182,13 +3182,14 @@
     }
 
     /**
-     * Get active data subscription id.
+     * Get active data subscription id. Active data subscription refers to the subscription
+     * currently chosen to provide cellular internet connection to the user. This may be
+     * different from getDefaultDataSubscriptionId(). Eg. Opportunistics data
+     *
      * See {@link PhoneStateListener#onActiveDataSubscriptionIdChanged(int)} for the details.
      *
-     * @return Active data subscription id
-     *
-     * //TODO: Refactor this API in b/134702460
-     * @hide
+     * @return Active data subscription id if any is chosen, or
+     * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not.
      */
     public static int getActiveDataSubscriptionId() {
         try {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d8c991f..864bf03 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -59,6 +59,7 @@
 import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
+import android.sysprop.TelephonyProperties;
 import android.telecom.CallScreeningService;
 import android.telecom.InCallService;
 import android.telecom.PhoneAccount;
@@ -98,7 +99,6 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.SmsApplication;
-import com.android.internal.telephony.TelephonyProperties;
 
 import dalvik.system.VMRuntime;
 
@@ -392,7 +392,7 @@
     @UnsupportedAppUsage
     public MultiSimVariants getMultiSimConfiguration() {
         String mSimConfig =
-            SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG);
+                TelephonyProperties.multi_sim_config().orElse("");
         if (mSimConfig.equals("dsds")) {
             return MultiSimVariants.DSDS;
         } else if (mSimConfig.equals("dsda")) {
@@ -458,8 +458,7 @@
      * {@link #getActiveModemCount} returns 1 while this API returns 2.
      */
     public @ModemCount int getSupportedModemCount() {
-        return SystemProperties.getInt(TelephonyProperties.PROPERTY_MAX_ACTIVE_MODEMS,
-                getActiveModemCount());
+        return TelephonyProperties.max_active_modems().orElse(getActiveModemCount());
     }
 
     /**
@@ -506,7 +505,7 @@
      */
     @Nullable
     public TelephonyManager createForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
-        int subId = getSubIdForPhoneAccountHandle(phoneAccountHandle);
+        int subId = getSubscriptionId(phoneAccountHandle);
         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
             return null;
         }
@@ -1704,8 +1703,8 @@
      *
      * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
      * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
+     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
+     * is an app that owns a managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -1745,8 +1744,8 @@
      *
      * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
      * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
+     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
+     * is an app that owns a managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -1805,7 +1804,8 @@
      *     <li>The caller holds the READ_PRIVILEGED_PHONE_STATE permission.</li>
      *     <li>If the caller is the device or profile owner, the caller holds the
      *     {@link Manifest.permission#READ_PHONE_STATE} permission.</li>
-     *     <li>The caller has carrier privileges (see {@link #hasCarrierPrivileges()}.</li>
+     *     <li>The caller has carrier privileges (see {@link #hasCarrierPrivileges()} on any
+     *     active subscription.</li>
      *     <li>The caller is the default SMS app for the device.</li>
      * </ul>
      * <p>The profile owner is an app that owns a managed profile on the device; for more details
@@ -1874,8 +1874,8 @@
      *
      * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
      * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
+     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
+     * is an app that owns a managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -1901,8 +1901,8 @@
      *
      * <p>Requires Permission: READ_PRIVILEGED_PHONE_STATE, for the calling app to be the device or
      * profile owner and have the READ_PHONE_STATE permission, or that the calling app has carrier
-     * privileges (see {@link #hasCarrierPrivileges}). The profile owner is an app that owns a
-     * managed profile on the device; for more details see <a
+     * privileges (see {@link #hasCarrierPrivileges}) on any active subscription. The profile owner
+     * is an app that owns a managed profile on the device; for more details see <a
      * href="https://developer.android.com/work/managed-profiles">Work profiles</a>. Profile owner
      * access is deprecated and will be removed in a future release.
      *
@@ -2255,12 +2255,10 @@
     /** {@hide} */
     @UnsupportedAppUsage
     private int getPhoneTypeFromProperty(int phoneId) {
-        String type = getTelephonyProperty(phoneId,
-                TelephonyProperties.CURRENT_ACTIVE_PHONE, null);
-        if (type == null || type.isEmpty()) {
-            return getPhoneTypeFromNetworkType(phoneId);
-        }
-        return Integer.parseInt(type);
+        Integer type = getTelephonyProperty(
+                phoneId, TelephonyProperties.current_active_phone(), null);
+        if (type != null) return type;
+        return getPhoneTypeFromNetworkType(phoneId);
     }
 
     private int getPhoneTypeFromNetworkType() {
@@ -2272,9 +2270,9 @@
         // When the system property CURRENT_ACTIVE_PHONE, has not been set,
         // use the system property for default network type.
         // This is a fail safe, and can only happen at first boot.
-        String mode = getTelephonyProperty(phoneId, "ro.telephony.default_network", null);
-        if (mode != null && !mode.isEmpty()) {
-            return TelephonyManager.getPhoneType(Integer.parseInt(mode));
+        Integer mode = getTelephonyProperty(phoneId, TelephonyProperties.default_network(), null);
+        if (mode != null) {
+            return TelephonyManager.getPhoneType(mode);
         }
         return TelephonyManager.PHONE_TYPE_NONE;
     }
@@ -2378,7 +2376,7 @@
 
     /** The ProductType used for LTE on CDMA devices */
     private static final String sLteOnCdmaProductType =
-        SystemProperties.get(TelephonyProperties.PROPERTY_LTE_ON_CDMA_PRODUCT_TYPE, "");
+            TelephonyProperties.lte_on_cdma_product_type().orElse("");
 
     /**
      * Return if the current radio is LTE on CDMA. This
@@ -2396,8 +2394,8 @@
         int curVal;
         String productType = "";
 
-        curVal = SystemProperties.getInt(TelephonyProperties.PROPERTY_LTE_ON_CDMA_DEVICE,
-                    PhoneConstants.LTE_ON_CDMA_UNKNOWN);
+        curVal = TelephonyProperties.lte_on_cdma_device().orElse(
+            PhoneConstants.LTE_ON_CDMA_UNKNOWN);
         retVal = curVal;
         if (retVal == PhoneConstants.LTE_ON_CDMA_UNKNOWN) {
             Matcher matcher = sProductTypePattern.matcher(sKernelCmdLine);
@@ -2449,7 +2447,7 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getNetworkOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.operator_alpha(), "");
     }
 
     /**
@@ -2493,7 +2491,7 @@
      **/
     @UnsupportedAppUsage
     public String getNetworkOperatorForPhone(int phoneId) {
-        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.operator_numeric(), "");
     }
 
 
@@ -2557,8 +2555,7 @@
     @UnsupportedAppUsage
     public boolean isNetworkRoaming(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
-        return Boolean.parseBoolean(getTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null));
+        return getTelephonyProperty(subId, TelephonyProperties.operator_is_roaming(), false);
     }
 
     /**
@@ -2605,6 +2602,8 @@
      *
      * @return the lowercase 2 character ISO-3166 country code, or empty string if not available.
      *
+     * @throws IllegalArgumentException when the slotIndex is invalid.
+     *
      * {@hide}
      */
     @SystemApi
@@ -2613,6 +2612,10 @@
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public String getNetworkCountryIso(int slotIndex) {
         try {
+            if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
+                throw new IllegalArgumentException("invalid slot index " + slotIndex);
+            }
+
             ITelephony telephony = getITelephony();
             if (telephony == null) return "";
             return telephony.getNetworkCountryIsoForPhone(slotIndex, getOpPackageName());
@@ -3512,8 +3515,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public String getSimOperatorNumericForPhone(int phoneId) {
-        return getTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.icc_operator_numeric(), "");
     }
 
     /**
@@ -3550,8 +3552,7 @@
      */
     @UnsupportedAppUsage
     public String getSimOperatorNameForPhone(int phoneId) {
-         return getTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.icc_operator_alpha(), "");
     }
 
     /**
@@ -3583,8 +3584,7 @@
      */
     @UnsupportedAppUsage
     public String getSimCountryIsoForPhone(int phoneId) {
-        return getTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.icc_operator_iso_country(), "");
     }
 
     /**
@@ -4226,6 +4226,7 @@
      * @hide
      * nobody seems to call this.
      */
+    @UnsupportedAppUsage
     @TestApi
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getLine1AlphaTag() {
@@ -6645,6 +6646,15 @@
     }
 
     /**
+     * Inserts or updates a list property. Expands the list if its length is not enough.
+     */
+    private static <T> List<T> updateTelephonyProperty(List<T> prop, int phoneId, T value) {
+        List<T> ret = new ArrayList<>(prop);
+        while (ret.size() <= phoneId) ret.add(null);
+        ret.set(phoneId, value);
+        return ret;
+    }
+    /**
      * Convenience function for retrieving a value from the secure settings
      * value list as an integer.  Note that internally setting values are
      * always stored as strings; this function converts the string to an
@@ -6735,7 +6745,7 @@
     }
 
     /**
-     * Gets a per-phone telephony property.
+     * Gets a per-phone telephony property from a property name.
      *
      * @hide
      */
@@ -6753,6 +6763,15 @@
     }
 
     /**
+     * Gets a typed per-phone telephony property from a schematized list property.
+     */
+    private static <T> T getTelephonyProperty(int phoneId, List<T> prop, T defaultValue) {
+        T ret = null;
+        if (phoneId >= 0 && phoneId < prop.size()) ret = prop.get(phoneId);
+        return ret != null ? ret : defaultValue;
+    }
+
+    /**
      * Gets a global telephony property.
      *
      * See also getTelephonyProperty(phoneId, property, defaultVal). Most telephony properties are
@@ -9080,7 +9099,7 @@
     }
 
    /**
-    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
+    * Set TelephonyProperties.icc_operator_numeric for the default phone.
     *
     * @hide
     */
@@ -9090,18 +9109,21 @@
     }
 
    /**
-    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the given phone.
+    * Set TelephonyProperties.icc_operator_numeric for the given phone.
     *
     * @hide
     */
     @UnsupportedAppUsage
     public void setSimOperatorNumericForPhone(int phoneId, String numeric) {
-        setTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, numeric);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.icc_operator_numeric(), phoneId, numeric);
+            TelephonyProperties.icc_operator_numeric(newList);
+        }
     }
 
     /**
-     * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
+     * Set TelephonyProperties.icc_operator_alpha for the default phone.
      *
      * @hide
      */
@@ -9111,18 +9133,21 @@
     }
 
     /**
-     * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the given phone.
+     * Set TelephonyProperties.icc_operator_alpha for the given phone.
      *
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setSimOperatorNameForPhone(int phoneId, String name) {
-        setTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, name);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.icc_operator_alpha(), phoneId, name);
+            TelephonyProperties.icc_operator_alpha(newList);
+        }
     }
 
    /**
-    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY for the default phone.
+    * Set TelephonyProperties.icc_operator_iso_country for the default phone.
     *
     * @hide
     */
@@ -9132,18 +9157,21 @@
     }
 
    /**
-    * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY for the given phone.
+    * Set TelephonyProperties.icc_operator_iso_country for the given phone.
     *
     * @hide
     */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setSimCountryIsoForPhone(int phoneId, String iso) {
-        setTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, iso);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.icc_operator_iso_country(), phoneId, iso);
+            TelephonyProperties.icc_operator_iso_country(newList);
+        }
     }
 
     /**
-     * Set TelephonyProperties.PROPERTY_SIM_STATE for the default phone.
+     * Set TelephonyProperties.sim_state for the default phone.
      *
      * @hide
      */
@@ -9153,14 +9181,17 @@
     }
 
     /**
-     * Set TelephonyProperties.PROPERTY_SIM_STATE for the given phone.
+     * Set TelephonyProperties.sim_state for the given phone.
      *
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setSimStateForPhone(int phoneId, String state) {
-        setTelephonyProperty(phoneId,
-                TelephonyProperties.PROPERTY_SIM_STATE, state);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.sim_state(), phoneId, state);
+            TelephonyProperties.sim_state(newList);
+        }
     }
 
     /**
@@ -9265,7 +9296,11 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setBasebandVersionForPhone(int phoneId, String version) {
-        setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_BASEBAND_VERSION, version);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.baseband_version(), phoneId, version);
+            TelephonyProperties.baseband_version(newList);
+        }
     }
 
     /**
@@ -9288,8 +9323,8 @@
      */
     private String getBasebandVersionLegacy(int phoneId) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            String prop = TelephonyProperties.PROPERTY_BASEBAND_VERSION +
-                    ((phoneId == 0) ? "" : Integer.toString(phoneId));
+            String prop = "gsm.version.baseband"
+                    + ((phoneId == 0) ? "" : Integer.toString(phoneId));
             return SystemProperties.get(prop);
         }
         return null;
@@ -9306,7 +9341,7 @@
         if (version != null && !version.isEmpty()) {
             setBasebandVersionForPhone(phoneId, version);
         }
-        return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_BASEBAND_VERSION, "");
+        return getTelephonyProperty(phoneId, TelephonyProperties.baseband_version(), "");
     }
 
     /**
@@ -9332,8 +9367,9 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setPhoneType(int phoneId, int type) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            TelephonyManager.setTelephonyProperty(phoneId,
-                    TelephonyProperties.CURRENT_ACTIVE_PHONE, String.valueOf(type));
+            List<Integer> newList = updateTelephonyProperty(
+                    TelephonyProperties.current_active_phone(), phoneId, type);
+            TelephonyProperties.current_active_phone(newList);
         }
     }
 
@@ -9362,8 +9398,8 @@
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public String getOtaSpNumberSchemaForPhone(int phoneId, String defaultValue) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            return TelephonyManager.getTelephonyProperty(phoneId,
-                    TelephonyProperties.PROPERTY_OTASP_NUM_SCHEMA, defaultValue);
+            return getTelephonyProperty(
+                    phoneId, TelephonyProperties.otasp_num_schema(), defaultValue);
         }
 
         return defaultValue;
@@ -9393,8 +9429,7 @@
      */
     public boolean getSmsReceiveCapableForPhone(int phoneId, boolean defaultValue) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            return Boolean.parseBoolean(TelephonyManager.getTelephonyProperty(phoneId,
-                    TelephonyProperties.PROPERTY_SMS_RECEIVE, String.valueOf(defaultValue)));
+            return getTelephonyProperty(phoneId, TelephonyProperties.sms_receive(), defaultValue);
         }
 
         return defaultValue;
@@ -9424,8 +9459,7 @@
      */
     public boolean getSmsSendCapableForPhone(int phoneId, boolean defaultValue) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            return Boolean.parseBoolean(TelephonyManager.getTelephonyProperty(phoneId,
-                    TelephonyProperties.PROPERTY_SMS_SEND, String.valueOf(defaultValue)));
+            return getTelephonyProperty(phoneId, TelephonyProperties.sms_send(), defaultValue);
         }
 
         return defaultValue;
@@ -9465,7 +9499,9 @@
     @UnsupportedAppUsage
     public void setNetworkOperatorNameForPhone(int phoneId, String name) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, name);
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.operator_alpha(), phoneId, name);
+            TelephonyProperties.operator_alpha(newList);
         }
     }
 
@@ -9487,7 +9523,11 @@
      */
     @UnsupportedAppUsage
     public void setNetworkOperatorNumericForPhone(int phoneId, String numeric) {
-        setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, numeric);
+        if (SubscriptionManager.isValidPhoneId(phoneId)) {
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.operator_numeric(), phoneId, numeric);
+            TelephonyProperties.operator_numeric(newList);
+        }
     }
 
     /**
@@ -9509,8 +9549,9 @@
     @UnsupportedAppUsage
     public void setNetworkRoamingForPhone(int phoneId, boolean isRoaming) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            setTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISROAMING,
-                    isRoaming ? "true" : "false");
+            List<Boolean> newList = updateTelephonyProperty(
+                    TelephonyProperties.operator_is_roaming(), phoneId, isRoaming);
+            TelephonyProperties.operator_is_roaming(newList);
         }
     }
 
@@ -9537,9 +9578,10 @@
     @UnsupportedAppUsage
     public void setDataNetworkTypeForPhone(int phoneId, int type) {
         if (SubscriptionManager.isValidPhoneId(phoneId)) {
-            setTelephonyProperty(phoneId,
-                    TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE,
+            List<String> newList = updateTelephonyProperty(
+                    TelephonyProperties.data_network_type(), phoneId,
                     ServiceState.rilRadioTechnologyToString(type));
+            TelephonyProperties.data_network_type(newList);
         }
     }
 
@@ -9592,7 +9634,7 @@
      *         permission.
      */
     @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
-    public int getSubIdForPhoneAccountHandle(@NonNull PhoneAccountHandle phoneAccountHandle) {
+    public int getSubscriptionId(@NonNull PhoneAccountHandle phoneAccountHandle) {
         int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         try {
             ITelephony service = getITelephony();
@@ -9601,7 +9643,7 @@
                         phoneAccountHandle, mContext.getOpPackageName());
             }
         } catch (RemoteException ex) {
-            Log.e(TAG, "getSubIdForPhoneAccountHandle RemoteException", ex);
+            Log.e(TAG, "getSubscriptionId RemoteException", ex);
             ex.rethrowAsRuntimeException();
         }
         return retval;
@@ -10724,6 +10766,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public int getCarrierIdListVersion() {
         try {
@@ -11612,6 +11655,7 @@
      *
      * @hide
      */
+    @UnsupportedAppUsage
     @TestApi
     public Pair<Integer, Integer> getRadioHalVersion() {
         try {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 0025c7a..cb66a96 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -189,6 +189,29 @@
             "android.telephony.euicc.action.RENAME_SUBSCRIPTION_PRIVILEGED";
 
     /**
+     * Intent action sent by a carrier app to launch the eSIM activation flow provided by the LPA UI
+     * (LUI). The carrier app must send this intent with one of the following:
+     *
+     * <p>{@link #EXTRA_USE_QR_SCANNER} not set or set to false: The LPA should try to get an
+     * activation code from the carrier app by binding to the carrier app service implementing
+     * {@link android.service.euicc.EuiccService#ACTION_BIND_CARRIER_PROVISIONING_SERVICE}.
+     * <p>{@link #EXTRA_USE_QR_SCANNER} set to true: The LPA should launch a QR scanner for the user
+     * to scan an eSIM profile QR code.
+     *
+     * <p>Upon completion, the LPA should return one of the following results to the carrier app:
+     *
+     * <p>{@code Activity.RESULT_OK}: The LPA has succeeded in downloading the new eSIM profile.
+     * <p>{@code Activity.RESULT_CANCELED}: The carrier app should treat this as if the user pressed
+     * the back button.
+     * <p>Anything else: The carrier app should treat this as an error.
+     *
+     * <p>LPA needs to check if caller's package name is allowed to perform this action.
+     **/
+    @SdkConstant(SdkConstant.SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_START_EUICC_ACTIVATION =
+            "android.telephony.euicc.action.START_EUICC_ACTIVATION";
+
+    /**
      * Result code for an operation indicating that the operation succeeded.
      */
     public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0;
@@ -342,10 +365,20 @@
      *
      * @hide
      */
-    // TODO: Make this a @SystemApi.
+    @SystemApi
     public static final String EXTRA_PHYSICAL_SLOT_ID =
             "android.telephony.euicc.extra.PHYSICAL_SLOT_ID";
 
+
+    /**
+     * Key for an extra set on actions {@link #ACTION_START_EUICC_ACTIVATION} providing a boolean
+     * value of whether to start eSIM activation with QR scanner.
+     *
+     * <p>Expected type of the extra data: boolean
+     **/
+    public static final String EXTRA_USE_QR_SCANNER =
+            "android.telephony.euicc.extra.USE_QR_SCANNER";
+
     /**
      * Optional meta-data attribute for a carrier app providing an icon to use to represent the
      * carrier. If not provided, the app's launcher icon will be used as a fallback.
@@ -830,7 +863,7 @@
      * @param callbackIntent a PendingIntent to launch when the operation completes.
      *
      * @deprecated From R, callers should specify a flag for specific set of subscriptions to erase
-     * and use {@link #eraseSubscriptionsWithOptions(int, PendingIntent)} instead
+     * and use {@link #eraseSubscriptions(int, PendingIntent)} instead
      *
      * @hide
      */
@@ -862,7 +895,7 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
-    public void eraseSubscriptionsWithOptions(
+    public void eraseSubscriptions(
             @ResetOption int options, @NonNull PendingIntent callbackIntent) {
         if (!isEnabled()) {
             sendUnavailableError(callbackIntent);
diff --git a/telephony/java/android/telephony/ims/ImsConferenceState.java b/telephony/java/android/telephony/ims/ImsConferenceState.java
index eb6c12c..8d2049b 100644
--- a/telephony/java/android/telephony/ims/ImsConferenceState.java
+++ b/telephony/java/android/telephony/ims/ImsConferenceState.java
@@ -24,7 +24,8 @@
 import android.os.Parcelable;
 import android.telecom.Call;
 import android.telecom.Connection;
-import android.telecom.Log;
+import android.telephony.Rlog;
+import android.util.Log;
 
 import java.util.HashMap;
 import java.util.Iterator;
@@ -39,6 +40,7 @@
 @SystemApi
 @TestApi
 public final class ImsConferenceState implements Parcelable {
+    private static final String TAG = "ImsConferenceState";
     /**
      * conference-info : user
      */
@@ -194,7 +196,7 @@
                 sb.append("<");
                 while (iterator.hasNext()) {
                     Entry<String, Bundle> entry = iterator.next();
-                    sb.append(Log.pii(entry.getKey()));
+                    sb.append(Rlog.pii(TAG, entry.getKey()));
                     sb.append(": ");
                     Bundle participantData = entry.getValue();
 
@@ -202,7 +204,7 @@
                         sb.append(key);
                         sb.append("=");
                         if (ENDPOINT.equals(key) || USER.equals(key)) {
-                            sb.append(Log.pii(participantData.get(key)));
+                            sb.append(Rlog.pii(TAG, participantData.get(key)));
                         } else {
                             sb.append(participantData.get(key));
                         }
diff --git a/telephony/java/android/telephony/ims/ImsExternalCallState.java b/telephony/java/android/telephony/ims/ImsExternalCallState.java
index 177d9b3..dcb9c9d 100644
--- a/telephony/java/android/telephony/ims/ImsExternalCallState.java
+++ b/telephony/java/android/telephony/ims/ImsExternalCallState.java
@@ -24,7 +24,6 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.telecom.Log;
 import android.telephony.Rlog;
 
 import java.lang.annotation.Retention;
@@ -219,8 +218,8 @@
     @Override
     public String toString() {
         return "ImsExternalCallState { mCallId = " + mCallId +
-                ", mAddress = " + Log.pii(mAddress) +
-                ", mLocalAddress = " + Log.pii(mLocalAddress) +
+                ", mAddress = " + Rlog.pii(TAG, mAddress) +
+                ", mLocalAddress = " + Rlog.pii(TAG, mLocalAddress) +
                 ", mIsPullable = " + mIsPullable +
                 ", mCallState = " + mCallState +
                 ", mCallType = " + mCallType +
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index eb0e2f7..5fd0af5 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -979,25 +979,25 @@
 
     /**
      * Get the status of the MmTel Feature registered on this subscription.
+     * @param executor The executor that will be used to call the callback.
      * @param callback A callback containing an Integer describing the current state of the
      *                 MmTel feature, Which will be one of the following:
      *                 {@link ImsFeature#STATE_UNAVAILABLE},
      *                {@link ImsFeature#STATE_INITIALIZING},
      *                {@link ImsFeature#STATE_READY}. Will be called using the executor
      *                 specified when the service state has been retrieved from the IMS service.
-     * @param executor The executor that will be used to call the callback.
      * @throws ImsException if the IMS service associated with this subscription is not available or
      * the IMS service is not available.
      */
     @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public void getFeatureState(@NonNull @ImsFeature.ImsState Consumer<Integer> callback,
-            @NonNull @CallbackExecutor Executor executor) throws ImsException {
-        if (callback == null) {
-            throw new IllegalArgumentException("Must include a non-null Consumer.");
-        }
+    public void getFeatureState(@NonNull @CallbackExecutor Executor executor,
+            @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException {
         if (executor == null) {
             throw new IllegalArgumentException("Must include a non-null Executor.");
         }
+        if (callback == null) {
+            throw new IllegalArgumentException("Must include a non-null Consumer.");
+        }
         try {
             getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
                 @Override
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 03ea920..22168c5 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -16,10 +16,12 @@
 
 package com.android.internal.telephony;
 
-import android.telephony.TelephonyManager;
+import android.sysprop.TelephonyProperties;
 
 import dalvik.annotation.compat.UnsupportedAppUsage;
 
+import java.util.Optional;
+
 /**
  * {@hide}
  */
@@ -233,8 +235,10 @@
     int NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 33;
 
     @UnsupportedAppUsage
-    int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
-            "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
+    int PREFERRED_NETWORK_MODE = Optional.of(TelephonyProperties.default_network())
+            .filter(list -> !list.isEmpty())
+            .map(list -> list.get(0))
+            .orElse(NETWORK_MODE_WCDMA_PREF);
 
     int BAND_MODE_UNSPECIFIED = 0;      //"unspecified" (selected by baseband automatically)
     int BAND_MODE_EURO = 1;             //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 67103bf..8a852ee 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -237,9 +237,10 @@
      * <ul>
      *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
      *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges.
-     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
-     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *       access check, or the calling package has carrier privileges on any active subscription.
+    *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
+     *       or carrier privileges of any active subscription.
      *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
      *       permission. In this case the caller would expect to have access to the device
      *       identifiers so false is returned instead of throwing a SecurityException to indicate
@@ -259,10 +260,10 @@
      * <ul>
      *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
      *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges.
+     *       access check, or the calling package has carrier privileges on any active subscription.
      *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
      *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission
-     *       or carrier privileges.
+     *       or carrier privileges of any active subscription.
      *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
      *       permission or carrier privileges. In this case the caller would expect to have access
      *       to the device identifiers so false is returned instead of throwing a SecurityException
@@ -271,8 +272,8 @@
      */
     public static boolean checkCallingOrSelfReadDeviceIdentifiers(Context context, int subId,
             String callingPackage, String message) {
-        return checkReadDeviceIdentifiers(context, TELEPHONY_SUPPLIER, subId,
-                Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+                context, subId, callingPackage, message, true);
     }
 
     /**
@@ -282,7 +283,7 @@
      * <ul>
      *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
      *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
-     *       access check, or the calling package has carrier privileges.
+     *       access check, or the calling package has carrier privileges on specified subscription.
      *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
      *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
      *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
@@ -293,21 +294,33 @@
      */
     public static boolean checkCallingOrSelfReadSubscriberIdentifiers(Context context, int subId,
             String callingPackage, String message) {
-        return checkReadDeviceIdentifiers(context, TELEPHONY_SUPPLIER, subId,
-                Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, message);
+        return checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+                context, subId, callingPackage, message, false);
     }
 
     /**
      * Checks whether the app with the given pid/uid can read device identifiers.
      *
-     * @returns true if the caller has the READ_PRIVILEGED_PHONE_STATE permission or the calling
-     * package passes a DevicePolicyManager Device Owner / Profile Owner device identifier access
-     * check.
+     * <p>This method behaves in one of the following ways:
+     * <ul>
+     *   <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the calling
+     *       package passes a DevicePolicyManager Device Owner / Profile Owner device identifier
+     *       access check; or the calling package has carrier privileges on the specified
+     *       subscription; or allowCarrierPrivilegeOnAnySub is true and has carrier privilege on
+     *       any active subscription.
+     *   <li>throw SecurityException: if the caller does not meet any of the requirements and is
+     *       targeting Q or is targeting pre-Q and does not have the READ_PHONE_STATE permission.
+     *   <li>return false: if the caller is targeting pre-Q and does have the READ_PHONE_STATE
+     *       permission. In this case the caller would expect to have access to the device
+     *       identifiers so false is returned instead of throwing a SecurityException to indicate
+     *       the calling function should return dummy data.
+     * </ul>
      */
-    @VisibleForTesting
-    public static boolean checkReadDeviceIdentifiers(Context context,
-            Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
-            String callingPackage, String message) {
+    private static boolean checkPrivilegedReadPermissionOrCarrierPrivilegePermission(
+            Context context, int subId, String callingPackage, String message,
+            boolean allowCarrierPrivilegeOnAnySub) {
+        int uid = Binder.getCallingUid();
+        int pid = Binder.getCallingPid();
         // Allow system and root access to the device identifiers.
         final int appId = UserHandle.getAppId(uid);
         if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) {
@@ -318,10 +331,17 @@
                 uid) == PackageManager.PERMISSION_GRANTED) {
             return true;
         }
-        // If the calling package has carrier privileges for any subscription then allow access.
-        if (checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid)) {
+
+        // If the calling package has carrier privileges for specified sub, then allow access.
+        if (checkCarrierPrivilegeForSubId(subId)) return true;
+
+        // If the calling package has carrier privileges for any subscription
+        // and allowCarrierPrivilegeOnAnySub is set true, then allow access.
+        if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(
+                context, TELEPHONY_SUPPLIER, uid)) {
             return true;
         }
+
         // if the calling package is not null then perform the DevicePolicyManager device /
         // profile owner and Appop checks.
         if (callingPackage != null) {
@@ -347,7 +367,7 @@
             }
         }
         return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage,
-            message);
+                message);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index b357fa4..6fc0228 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -16,10 +16,8 @@
 
 package com.android.internal.telephony.cdma;
 
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
-
 import android.content.res.Resources;
-import android.os.SystemProperties;
+import android.sysprop.TelephonyProperties;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.Rlog;
 import android.telephony.SmsCbLocation;
@@ -34,7 +32,6 @@
 import com.android.internal.telephony.SmsConstants;
 import com.android.internal.telephony.SmsHeader;
 import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.cdma.sms.BearerData;
 import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
 import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
@@ -862,7 +859,7 @@
         // TODO: Skip it for EF SMS(SUBMIT and DELIVER) because the IDD depends on current network?
         // 2) Adds the '+' prefix if TON is International
         // 3) Keeps the '+' if address starts with the '+'
-        String idd = SystemProperties.get(PROPERTY_OPERATOR_IDP_STRING, null);
+        String idd = TelephonyProperties.operator_idp_string().orElse(null);
         addr.address = new String(addr.origBytes);
         if (!TextUtils.isEmpty(idd) && addr.address.startsWith(idd)) {
             addr.address = "+" + addr.address.substring(idd.length());
@@ -939,14 +936,13 @@
         // msgId==0 is (sometimes?) treated specially by lower levels.
         // Specifically, the ID is not preserved for delivery ACKs.
         // Hence, avoid 0 -- constraining the range to 1..65535.
-        int msgId = SystemProperties.getInt(TelephonyProperties.PROPERTY_CDMA_MSG_ID, 1);
-        String nextMsgId = Integer.toString((msgId % 0xFFFF) + 1);
+        int msgId = TelephonyProperties.cdma_msg_id().orElse(1);
+        int nextMsgId = msgId % 0xFFFF + 1;
         try{
-            SystemProperties.set(TelephonyProperties.PROPERTY_CDMA_MSG_ID, nextMsgId);
+            TelephonyProperties.cdma_msg_id(nextMsgId);
             if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
-                Rlog.d(LOG_TAG, "next " + TelephonyProperties.PROPERTY_CDMA_MSG_ID + " = " + nextMsgId);
-                Rlog.d(LOG_TAG, "readback gets " +
-                        SystemProperties.get(TelephonyProperties.PROPERTY_CDMA_MSG_ID));
+                Rlog.d(LOG_TAG, "next persist.radio.cdma.msgid = " + nextMsgId);
+                Rlog.d(LOG_TAG, "readback gets " + TelephonyProperties.cdma_msg_id().orElse(1));
             }
         } catch(RuntimeException ex) {
             Rlog.e(LOG_TAG, "set nextMessage ID failed: " + ex);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
index cbe5211..216f616 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbHeader.java
@@ -33,7 +33,7 @@
  * All relevant header information is now sent as a Parcelable
  * {@link android.telephony.SmsCbMessage} object in the "message" extra of the
  * {@link android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION} or
- * {@link android.provider.Telephony.Sms.Intents#SMS_EMERGENCY_CB_RECEIVED_ACTION} intent.
+ * {@link android.provider.Telephony.Sms.Intents#ACTION_SMS_EMERGENCY_CB_RECEIVED} intent.
  * The raw PDU is no longer sent to SMS CB applications.
  */
 public class SmsCbHeader {
diff --git a/test-mock/Android.bp b/test-mock/Android.bp
index 0b5d446..aa4174a 100644
--- a/test-mock/Android.bp
+++ b/test-mock/Android.bp
@@ -27,7 +27,10 @@
         ":framework-core-sources-for-test-mock",
         ":framework_native_aidl",
     ],
-    libs: ["framework-all"],
+    libs: [
+        "framework-all",
+        "app-compat-annotations",
+    ],
 
     api_packages: [
         "android.test.mock",
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index a70152c..8283019 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -16,6 +16,8 @@
 
 package android.test.mock;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.ContentProvider;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -130,17 +132,47 @@
     }
 
     /**
-     * Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
-     * ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
-     * The method hides providers linked to MockContentResolver from other observers in the system.
-     *
-     * @param uri (Ignored) The uri of the content provider.
-     * @param observer (Ignored) The observer that originated the change.
-     * @param syncToNetwork (Ignored) If true, attempt to sync the change to the network.
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
      */
     @Override
-    public void notifyChange(Uri uri,
-            ContentObserver observer,
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     *
+     * @deprecated callers should consider migrating to
+     *             {@link #notifyChange(Uri, ContentObserver, int)}, as it
+     *             offers support for many more options than just
+     *             {@link #NOTIFY_SYNC_TO_NETWORK}.
+     */
+    @Override
+    @Deprecated
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
             boolean syncToNetwork) {
     }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     */
+    @Override
+    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+    }
+
+    /**
+     * Overrides the behavior from the parent class to completely ignore any
+     * content notifications sent to this object. This effectively hides clients
+     * from observers elsewhere in the system.
+     */
+    @Override
+    public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+            @NotifyFlags int flags) {
+    }
 }
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 1de6260..45b236c 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -535,6 +535,14 @@
 
     /** @hide */
     @Override
+    @SystemApi
+    public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
+            IntentFilter filter, String broadcastPermission, Handler scheduler) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
     public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
             IntentFilter filter, String broadcastPermission, Handler scheduler) {
         throw new UnsupportedOperationException();
diff --git a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
index 74aaec1..10f3e54 100644
--- a/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
+++ b/tests/BootImageProfileTest/src/com/android/bootimageprofile/BootImageProfileTest.java
@@ -73,53 +73,67 @@
         res = mTestDevice.executeShellCommand("truncate -s 0 " + SYSTEM_SERVER_PROFILE).trim();
         assertTrue(res, res.length() == 0);
         // Wait up to 20 seconds for the profile to be saved.
-        for (int i = 0; i < 20; ++i) {
+        final int numIterations = 20;
+        for (int i = 1; i <= numIterations; ++i) {
             // Force save the profile since we truncated it.
             if (forceSaveProfile("system_server")) {
                 // Might fail if system server is not yet running.
                 String s = mTestDevice.executeShellCommand(
                         "wc -c <" + SYSTEM_SERVER_PROFILE).trim();
-                if (!"0".equals(s)) {
-                    break;
+                if ("0".equals(s)) {
+                    Thread.sleep(1000);
+                    continue;
                 }
             }
+
+            // In case the profile is partially saved, wait an extra second.
             Thread.sleep(1000);
-        }
-        // In case the profile is partially saved, wait an extra second.
-        Thread.sleep(1000);
-        // Validate that the profile is non empty.
-        res = mTestDevice.executeShellCommand("profman --dump-only --profile-file="
-                + SYSTEM_SERVER_PROFILE);
-        boolean sawFramework = false;
-        boolean sawServices = false;
-        for (String line : res.split("\n")) {
-            if (line.contains("framework.jar")) {
-                sawFramework = true;  // Legacy
-            } else if (line.contains("framework-minus-apex.jar")) {
-                sawFramework = true;
-            } else if (line.contains("services.jar")) {
-                sawServices = true;
+
+            // Validate that the profile is non empty.
+            res = mTestDevice.executeShellCommand("profman --dump-only --profile-file="
+                    + SYSTEM_SERVER_PROFILE);
+            boolean sawFramework = false;
+            boolean sawServices = false;
+            for (String line : res.split("\n")) {
+                if (line.contains("framework.jar")) {
+                    sawFramework = true;
+                } else if (line.contains("framework-minus-apex.jar")) {
+                    sawFramework = true;
+                } else if (line.contains("services.jar")) {
+                    sawServices = true;
+                }
+            }
+            if (i == numIterations) {
+                // Only assert for last iteration since there are race conditions where the package
+                // manager might not be started whewn the profile saves.
+                assertTrue("Did not see framework.jar in " + res, sawFramework);
+                assertTrue("Did not see services.jar in " + res, sawServices);
+            }
+
+            // Test the profile contents contain common methods for core-oj that would normally be
+            // AOT compiled. Also test that services.jar has PackageManagerService.<init> since the
+            // package manager service should always be created during boot.
+            res = mTestDevice.executeShellCommand(
+                    "profman --dump-classes-and-methods --profile-file="
+                    + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"
+                    + " --apk=/system/framework/services.jar");
+            boolean sawObjectInit = false;
+            boolean sawPmInit = false;
+            for (String line : res.split("\n")) {
+                if (line.contains("Ljava/lang/Object;-><init>()V")) {
+                    sawObjectInit = true;
+                } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) {
+                    sawPmInit = true;
+                }
+            }
+            if (i == numIterations) {
+                assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
+                assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit);
+            }
+
+            if (sawFramework && sawServices && sawObjectInit && sawPmInit) {
+                break;  // Asserts passed, exit.
             }
         }
-        assertTrue("Did not see framework.jar in " + res, sawFramework);
-        assertTrue("Did not see services.jar in " + res, sawServices);
-
-
-        // Test the profile contents contain common methods for core-oj that would normally be AOT
-        // compiled.
-        res = mTestDevice.executeShellCommand("profman --dump-classes-and-methods --profile-file="
-                + SYSTEM_SERVER_PROFILE + " --apk=/apex/com.android.art/javalib/core-oj.jar"
-                + " --apk=/system/framework/services.jar");
-        boolean sawObjectInit = false;
-        boolean sawPmInit = false;
-        for (String line : res.split("\n")) {
-            if (line.contains("Ljava/lang/Object;-><init>()V")) {
-                sawObjectInit = true;
-            } else if (line.contains("Lcom/android/server/pm/PackageManagerService;-><init>")) {
-                sawPmInit = true;
-            }
-        }
-        assertTrue("Did not see Object.<init> in " + res, sawObjectInit);
-        assertTrue("Did not see PackageManagerService.<init> in " + res, sawPmInit);
     }
 }
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/FlickerTests/TEST_MAPPING b/tests/FlickerTests/TEST_MAPPING
index f34c432..db251b9 100644
--- a/tests/FlickerTests/TEST_MAPPING
+++ b/tests/FlickerTests/TEST_MAPPING
@@ -1,8 +1,13 @@
 {
   "postsubmit": [
+    // Run tests on real device
     {
       "name": "FlickerTests",
       "keywords": ["primary-device"]
+    },
+    // Also run the tests in the cloud
+    {
+      "name": "FlickerTests"
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
index fd31aa5..e033d0a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
@@ -78,6 +78,7 @@
         return TransitionRunner.newBuilder()
                 .withTag("OpenAppWarm_" + testApp.getLauncherName()
                         + rotationToString(beginRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBeforeAll(() -> setRotation(device, beginRotation))
                 .runBeforeAll(testApp::open)
@@ -94,6 +95,7 @@
             device) {
         return TransitionRunner.newBuilder()
                 .withTag("closeAppWithBackKey_" + testApp.getLauncherName())
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(testApp::open)
                 .runBefore(device::waitForIdle)
@@ -108,6 +110,7 @@
             device) {
         return TransitionRunner.newBuilder()
                 .withTag("closeAppWithHomeKey_" + testApp.getLauncherName())
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(testApp::open)
                 .runBefore(device::waitForIdle)
@@ -123,6 +126,7 @@
         return TransitionRunner.newBuilder()
                 .withTag("OpenAppCold_" + testApp.getLauncherName()
                         + rotationToString(beginRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBeforeAll(() -> setRotation(device, beginRotation))
@@ -140,6 +144,7 @@
                 .withTag("changeAppRotation_" + testApp.getLauncherName()
                         + rotationToString(beginRotation) + "_" +
                         rotationToString(endRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBeforeAll(testApp::open)
                 .runBefore(() -> setRotation(device, beginRotation))
@@ -156,6 +161,7 @@
                 rotationToString(beginRotation) + "_" + rotationToString(endRotation);
         return TransitionRunner.newBuilder()
                 .withTag(testTag)
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBeforeAll(() -> {
                             context.startActivity(intent);
@@ -173,6 +179,7 @@
     static TransitionBuilder appToSplitScreen(IAppHelper testApp, UiDevice device) {
         return TransitionRunner.newBuilder()
                 .withTag("appToSplitScreen_" + testApp.getLauncherName())
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(testApp::open)
                 .runBefore(device::waitForIdle)
@@ -186,6 +193,7 @@
     static TransitionBuilder splitScreenToLauncher(IAppHelper testApp, UiDevice device) {
         return TransitionRunner.newBuilder()
                 .withTag("splitScreenToLauncher_" + testApp.getLauncherName())
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(testApp::open)
                 .runBefore(device::waitForIdle)
@@ -200,6 +208,7 @@
         return TransitionRunner.newBuilder()
                 .withTag("editTextSetFocus_" + testApp.getLauncherName()
                         + rotationToString(beginRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(() -> setRotation(device, beginRotation))
@@ -218,6 +227,7 @@
                 + rotationToString(beginRotation);
         return TransitionRunner.newBuilder()
                 .withTag(testTag)
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBeforeAll(() -> setRotation(device, beginRotation))
                 .runBeforeAll(() -> clearRecents(device))
@@ -246,6 +256,7 @@
         return TransitionRunner.newBuilder()
                 .withTag("editTextLoseFocusToHome_" + testApp.getLauncherName()
                         + rotationToString(beginRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(() -> setRotation(device, beginRotation))
@@ -262,6 +273,7 @@
         return TransitionRunner.newBuilder()
                 .withTag("editTextLoseFocusToApp_" + testApp.getLauncherName()
                         + rotationToString(beginRotation))
+                .recordAllRuns()
                 .runBeforeAll(AutomationUtils::wakeUpAndGoToHomeScreen)
                 .runBefore(device::pressHome)
                 .runBefore(() -> setRotation(device, beginRotation))
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 06be5e2..3be7a4a 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -77,8 +77,15 @@
 
     private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
     private static final TestApp NETWORK_STACK = new TestApp("NetworkStack",
-            getNetworkStackPackageName(), -1, false,
-            new File("/system/priv-app/NetworkStack/NetworkStack.apk"));
+            getNetworkStackPackageName(), -1, false, findNetworkStackApk());
+
+    private static File findNetworkStackApk() {
+        final File apk = new File("/system/priv-app/NetworkStack/NetworkStack.apk");
+        if (apk.isFile()) {
+            return apk;
+        }
+        return new File("/system/priv-app/NetworkStackNext/NetworkStackNext.apk");
+    }
 
     /**
      * Adopts common shell permissions needed for rollback tests.
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index 557d498..e4a8feb 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -139,7 +139,7 @@
                 + "watchdog_request_timeout_millis 300000");
         // Simulate re-installation of new NetworkStack with rollbacks enabled
         getDevice().executeShellCommand("pm install -r --staged --enable-rollback "
-                + "/system/priv-app/NetworkStack/NetworkStack.apk");
+                + getNetworkStackPath());
 
         // Sleep to allow writes to disk before reboot
         Thread.sleep(5000);
@@ -188,4 +188,9 @@
             lastPid = pid;
         }
     }
+
+    private String getNetworkStackPath() throws Exception {
+        // Find the NetworkStack path (can be NetworkStack.apk or NetworkStackNext.apk)
+        return getDevice().executeShellCommand("ls /system/priv-app/NetworkStack*/*.apk");
+    }
 }
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index cd04c2e..3d72ee6 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -18,13 +18,13 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.view.View;
-import android.content.Intent;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
+import android.content.Intent;
 import android.os.Handler;
-import android.util.Log;
 import android.os.SystemClock;
+import android.util.Log;
+import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 
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/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index 91b3cd9..4dd3b5a 100644
--- a/tests/net/integration/AndroidManifest.xml
+++ b/tests/net/integration/AndroidManifest.xml
@@ -17,7 +17,6 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          xmlns:tools="http://schemas.android.com/tools"
           package="com.android.server.net.integrationtests">
 
     <!-- For ConnectivityService registerReceiverAsUser (receiving broadcasts) -->
@@ -26,13 +25,19 @@
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <!-- ConnectivityService sends notifications to BatteryStats -->
     <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <!-- Reading network status -->
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+    <!-- Reading DeviceConfig flags -->
+    <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
 
         <!-- This manifest is merged with the base manifest of the real NetworkStack app.
              Remove the NetworkStackService from the base (real) manifest, and replace with a test
              service that responds to the same intent -->
-        <service android:name="com.android.server.NetworkStackService" tools:node="remove"/>
         <service android:name=".TestNetworkStackService"
                  android:process="com.android.server.net.integrationtests.testnetworkstack">
             <intent-filter>
@@ -45,9 +50,9 @@
                 <action android:name=".INetworkStackInstrumentation"/>
             </intent-filter>
         </service>
-        <service tools:replace="android:process"
-                 android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
-                 android:process="com.android.server.net.integrationtests.testnetworkstack"/>
+        <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+                 android:process="com.android.server.net.integrationtests.testnetworkstack"
+                 android:permission="android.permission.BIND_JOB_SERVICE"/>
 
     </application>
 
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/tests/touchlag/Android.bp b/tests/touchlag/Android.bp
deleted file mode 100644
index 092eea9..0000000
--- a/tests/touchlag/Android.bp
+++ /dev/null
@@ -1,14 +0,0 @@
-cc_test {
-    name: "test-touchlag",
-    gtest: false,
-    srcs: ["touchlag.cpp"],
-    shared_libs: [
-        "libcutils",
-        "libutils",
-    ],
-    cflags: [
-        "-Wall",
-        "-Wextra",
-        "-Werror",
-    ],
-}
diff --git a/tests/touchlag/touchlag.cpp b/tests/touchlag/touchlag.cpp
deleted file mode 100644
index 9264a25..0000000
--- a/tests/touchlag/touchlag.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/fb.h>
-#include <linux/input.h>
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <cutils/memory.h>
-#include <asm-generic/mman.h>
-#include <sys/mman.h>
-#include <utils/threads.h>
-#include <unistd.h>
-#include <math.h>
-
-using namespace android;
-
-#ifndef FBIO_WAITFORVSYNC
-#define FBIO_WAITFORVSYNC   _IOW('F', 0x20, __u32)
-#endif
-
-struct Buffer {
-    size_t w;
-    size_t h;
-    size_t s;
-    union {
-        void* addr;
-        uint32_t* pixels;
-    };
-};
-
-void clearBuffer(Buffer* buf, uint32_t pixel) {
-    android_memset32(buf->pixels, pixel, buf->s * buf->h * 4);
-}
-
-void drawTwoPixels(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
-    if (y>0 && y<ssize_t(buf->h)) {
-        uint32_t* bits = buf->pixels + y * buf->s;
-        if (x>=0 && x<ssize_t(buf->w)) {
-            bits[x] = pixel;
-        }
-        ssize_t W(w);
-        if ((x+W)>=0 && (x+W)<ssize_t(buf->w)) {
-            bits[x+W] = pixel;
-        }
-    }
-}
-
-void drawHLine(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w) {
-    if (y>0 && y<ssize_t(buf->h)) {
-        ssize_t W(w);
-        if (x<0) {
-            W += x;
-            x = 0;
-        }
-        if (x+w > buf->w) {
-            W = buf->w - x;
-        }
-        if (W>0) {
-            uint32_t* bits = buf->pixels + y * buf->s + x;
-            android_memset32(bits, pixel, W*4);
-        }
-    }
-}
-
-void drawRect(Buffer* buf, uint32_t pixel, ssize_t x, ssize_t y, size_t w, size_t h) {
-    ssize_t W(w), H(h);
-    if (x<0) {
-        w += x;
-        x = 0;
-    }
-    if (y<0) {
-        h += y;
-        y = 0;
-    }
-    if (x+w > buf->w)   W = buf->w - x;
-    if (y+h > buf->h)   H = buf->h - y;
-    if (W>0 && H>0) {
-        uint32_t* bits = buf->pixels + y * buf->s + x;
-        for (ssize_t i=0 ; i<H ; i++) {
-            android_memset32(bits, pixel, W*4);
-            bits += buf->s;
-        }
-    }
-}
-
-void drawCircle(Buffer* buf, uint32_t pixel,
-        size_t x0, size_t y0, size_t radius, bool filled = false) {
-    ssize_t f = 1 - radius;
-    ssize_t ddF_x = 1;
-    ssize_t ddF_y = -2 * radius;
-    ssize_t x = 0;
-    ssize_t y = radius;
-    if (filled) {
-        drawHLine(buf, pixel, x0-radius, y0, 2*radius);
-    } else {
-        drawTwoPixels(buf, pixel, x0-radius, y0, 2*radius);
-    }
-    while (x < y) {
-        if (f >= 0) {
-            y--;
-            ddF_y += 2;
-            f += ddF_y;
-        }
-        x++;
-        ddF_x += 2;
-        f += ddF_x;
-        if (filled) {
-            drawHLine(buf, pixel, x0-x, y0+y, 2*x);
-            drawHLine(buf, pixel, x0-x, y0-y, 2*x);
-            drawHLine(buf, pixel, x0-y, y0+x, 2*y);
-            drawHLine(buf, pixel, x0-y, y0-x, 2*y);
-        } else {
-            drawTwoPixels(buf, pixel, x0-x, y0+y, 2*x);
-            drawTwoPixels(buf, pixel, x0-x, y0-y, 2*x);
-            drawTwoPixels(buf, pixel, x0-y, y0+x, 2*y);
-            drawTwoPixels(buf, pixel, x0-y, y0-x, 2*y);
-        }
-    }
-}
-
-class TouchEvents {
-    class EventThread : public Thread {
-        int fd;
-
-        virtual bool threadLoop() {
-            input_event event;
-            int first_down = 0;
-            do {
-                read(fd, &event, sizeof(event));
-                if (event.type == EV_ABS) {
-                    if (event.code == ABS_MT_TRACKING_ID) {
-                        down = event.value == -1 ? 0 : 1;
-                        first_down = down;
-                    }
-                    if (event.code == ABS_MT_POSITION_X) {
-                        x = event.value;
-                    }
-                    if (event.code == ABS_MT_POSITION_Y) {
-                        y = event.value;
-                    }
-                }
-            } while (event.type == EV_SYN);
-            return true;
-        }
-
-    public:
-        int x, y, down;
-        EventThread() : Thread(false),
-                x(0), y(0), down(0)
-        {
-            fd = open("/dev/input/event1", O_RDONLY);
-        }
-};
-    sp<EventThread> thread;
-
-public:
-    TouchEvents() {
-        thread = new EventThread();
-        thread->run("EventThread", PRIORITY_URGENT_DISPLAY);
-    }
-
-    int getMostRecentPosition(int* x, int* y) {
-        *x = thread->x;
-        *y = thread->y;
-        return thread->down;
-    }
-};
-
-
-struct Queue {
-    struct position {
-        int x, y;
-    };
-    int index;
-    position q[16];
-    Queue() : index(0) { }
-    void push(int x, int y) {
-        index++;
-        index &= 0xF;
-        q[index].x = x;
-        q[index].y = y;
-    }
-    void get(int lag, int* x, int* y) {
-        const int i = (index - lag) & 0xF;
-        *x = q[i].x;
-        *y = q[i].y;
-    }
-};
-
-extern char *optarg;
-extern int optind;
-extern int optopt;
-extern int opterr;
-extern int optreset;
-
-void usage(const char* name) {
-    printf("\nusage: %s [-h] [-l lag]\n", name);
-}
-
-int main(int argc, char** argv) {
-    fb_var_screeninfo vi;
-    fb_fix_screeninfo fi;
-
-    int lag = 0;
-    int fd = open("/dev/graphics/fb0", O_RDWR);
-    ioctl(fd, FBIOGET_VSCREENINFO, &vi);
-    ioctl(fd, FBIOGET_FSCREENINFO, &fi);
-    void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-    Buffer framebuffer;
-    framebuffer.w = vi.xres;
-    framebuffer.h = vi.yres;
-    framebuffer.s = fi.line_length / (vi.bits_per_pixel >> 3);
-    framebuffer.addr = bits;
-
-    int ch;
-    while ((ch = getopt(argc, argv, "hl:")) != -1) {
-        switch (ch) {
-            case 'l':
-                lag = atoi(optarg);
-                break;
-            case 'h':
-            default:
-                usage(argv[0]);
-                exit(0);
-        }
-    }
-    argc -= optind;
-    argv += optind;
-
-
-    TouchEvents touch;
-    Queue queue;
-
-
-    int x=0, y=0;
-    int lag_x=0, lag_y=0;
-
-    clearBuffer(&framebuffer, 0);
-    while (true) {
-        uint32_t crt = 0;
-        ioctl(fd, FBIO_WAITFORVSYNC, &crt);
-
-        // draw beam marker
-        drawRect(&framebuffer, 0x400000, framebuffer.w-2, 0, 2, framebuffer.h);
-        // erase screen
-        if (lag) {
-            drawCircle(&framebuffer, 0, lag_x, lag_y, 100);
-            drawHLine(&framebuffer, 0, 0, lag_y, 32);
-        }
-        drawCircle(&framebuffer, 0, x, y, 100, true);
-        drawHLine(&framebuffer, 0, 0, y, 32);
-
-        // draw a line at y=1000
-        drawHLine(&framebuffer, 0x808080, 0, 1000, framebuffer.w);
-
-        // get touch events
-        touch.getMostRecentPosition(&x, &y);
-        queue.push(x, y);
-        queue.get(lag, &lag_x, &lag_y);
-
-        if (lag) {
-            drawCircle(&framebuffer, 0x00FF00, lag_x, lag_y, 100);
-            drawHLine(&framebuffer, 0x00FF00, 0, lag_y, 32);
-        }
-
-        drawCircle(&framebuffer, 0xFFFFFF, x, y, 100, true);
-        drawHLine(&framebuffer, 0xFFFFFF, 0, y, 32);
-
-        // draw end of frame beam marker
-        drawRect(&framebuffer, 0x004000, framebuffer.w-2, 0, 2, framebuffer.h);
-    }
-
-    close(fd);
-    return 0;
-}
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 1be4ea8..6f44230 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -210,6 +210,7 @@
     tools: [":soong_zip"],
     srcs: [
         "Configuration.proto",
+        "ResourcesInternal.proto",
         "Resources.proto",
     ],
     out: ["aapt2-protos.zip"],
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 ")
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bc73a93f1..bbb8544 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -64,9 +64,9 @@
      */
     oneway void requestActivityInfo(in ResultReceiver result);
 
-    ParceledListSlice getConfiguredNetworks(String packageName);
+    ParceledListSlice getConfiguredNetworks(String packageName, String featureId);
 
-    ParceledListSlice getPrivilegedConfiguredNetworks(String packageName);
+    ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId);
 
     Map getAllMatchingFqdnsForScanResults(in List<ScanResult> scanResult);
 
@@ -98,9 +98,9 @@
 
     void allowAutojoin(int netId, boolean choice);
 
-    boolean startScan(String packageName);
+    boolean startScan(String packageName, String featureId);
 
-    List<ScanResult> getScanResults(String callingPackage);
+    List<ScanResult> getScanResults(String callingPackage, String callingFeatureId);
 
     boolean disconnect(String packageName);
 
@@ -108,7 +108,7 @@
 
     boolean reassociate(String packageName);
 
-    WifiInfo getConnectionInfo(String callingPackage);
+    WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId);
 
     boolean setWifiEnabled(String packageName, boolean enable);
 
@@ -145,7 +145,7 @@
     boolean stopSoftAp();
 
     int startLocalOnlyHotspot(in ILocalOnlyHotspotCallback callback, String packageName,
-                              in SoftApConfiguration customConfig);
+                              String featureId, in SoftApConfiguration customConfig);
 
     void stopLocalOnlyHotspot();
 
@@ -206,7 +206,8 @@
 
     void unregisterNetworkRequestMatchCallback(int callbackIdentifier);
 
-    int addNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName);
+    int addNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName,
+        in String featureId);
 
     int removeNetworkSuggestions(in List<WifiNetworkSuggestion> networkSuggestions, in String packageName);
 
@@ -238,7 +239,7 @@
 
     void unregisterScanResultsListener(int listenerIdentifier);
 
-    void registerSuggestionConnectionStatusListener(in IBinder binder, in ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName);
+    void registerSuggestionConnectionStatusListener(in IBinder binder, in ISuggestionConnectionStatusListener listener, int listenerIdentifier, String packageName, String featureId);
 
     void unregisterSuggestionConnectionStatusListener(int listenerIdentifier, String packageName);
 }
diff --git a/wifi/java/android/net/wifi/IWifiScanner.aidl b/wifi/java/android/net/wifi/IWifiScanner.aidl
index 114c732..485f5ce 100644
--- a/wifi/java/android/net/wifi/IWifiScanner.aidl
+++ b/wifi/java/android/net/wifi/IWifiScanner.aidl
@@ -26,5 +26,5 @@
 {
     Messenger getMessenger();
 
-    Bundle getAvailableChannels(int band, String packageName);
+    Bundle getAvailableChannels(int band, String packageName, String featureId);
 }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 30c24d3..90343d4 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2627,7 +2627,6 @@
         out.writeInt(apBand);
         out.writeInt(apChannel);
         BackupUtils.writeString(out, preSharedKey);
-        BackupUtils.writeString(out, saePasswordId);
         out.writeInt(getAuthType());
         out.writeBoolean(hiddenSSID);
         return baos.toByteArray();
@@ -2651,7 +2650,6 @@
         config.apBand = in.readInt();
         config.apChannel = in.readInt();
         config.preSharedKey = BackupUtils.readString(in);
-        config.saePasswordId = BackupUtils.readString(in);
         config.allowedKeyManagement.set(in.readInt());
         if (version >= 3) {
             config.hiddenSSID = in.readBoolean();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 2cf3b59..93960de 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1254,7 +1254,8 @@
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return Collections.emptyList();
             ParceledListSlice<WifiConfiguration> parceledList =
-                    iWifiManager.getConfiguredNetworks(mContext.getOpPackageName());
+                    iWifiManager.getConfiguredNetworks(mContext.getOpPackageName(),
+                            mContext.getFeatureId());
             if (parceledList == null) {
                 return Collections.emptyList();
             }
@@ -1272,7 +1273,8 @@
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return Collections.emptyList();
             ParceledListSlice<WifiConfiguration> parceledList =
-                    iWifiManager.getPrivilegedConfiguredNetworks(mContext.getOpPackageName());
+                    iWifiManager.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
+                            mContext.getFeatureId());
             if (parceledList == null) {
                 return Collections.emptyList();
             }
@@ -1764,7 +1766,7 @@
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL;
             return iWifiManager.addNetworkSuggestions(
-                    networkSuggestions, mContext.getOpPackageName());
+                    networkSuggestions, mContext.getOpPackageName(), mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2246,11 +2248,15 @@
     /** @hide */
     public static final long WIFI_FEATURE_DPP              = 0x80000000L; // DPP (Easy-Connect)
     /** @hide */
-    public static final long WIFI_FEATURE_P2P_RAND_MAC    = 0x100000000L; // Random P2P MAC
+    public static final long WIFI_FEATURE_P2P_RAND_MAC     = 0x100000000L; // Random P2P MAC
     /** @hide */
     public static final long WIFI_FEATURE_CONNECTED_RAND_MAC    = 0x200000000L; // Random STA MAC
     /** @hide */
-    public static final long WIFI_FEATURE_AP_RAND_MAC    = 0x400000000L; // Random AP MAC
+    public static final long WIFI_FEATURE_AP_RAND_MAC      = 0x400000000L; // Random AP MAC
+    /** @hide */
+    public static final long WIFI_FEATURE_MBO              = 0x800000000L; // MBO Support
+    /** @hide */
+    public static final long WIFI_FEATURE_OCE              = 0x1000000000L; // OCE Support
 
     private long getSupportedFeatures() {
         try {
@@ -2449,7 +2455,8 @@
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return false;
             String packageName = mContext.getOpPackageName();
-            return iWifiManager.startScan(packageName);
+            String featureId = mContext.getFeatureId();
+            return iWifiManager.startScan(packageName, featureId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2480,7 +2487,8 @@
         try {
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return null;
-            return iWifiManager.getConnectionInfo(mContext.getOpPackageName());
+            return iWifiManager.getConnectionInfo(mContext.getOpPackageName(),
+                    mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2496,7 +2504,8 @@
         try {
             IWifiManager iWifiManager = getIWifiManager();
             if (iWifiManager == null) return Collections.emptyList();
-            return iWifiManager.getScanResults(mContext.getOpPackageName());
+            return iWifiManager.getScanResults(mContext.getOpPackageName(),
+                    mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2914,7 +2923,9 @@
                     throw new RemoteException("Wifi service is not running");
                 }
                 String packageName = mContext.getOpPackageName();
-                int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName, config);
+                String featureId = mContext.getFeatureId();
+                int returnCode = iWifiManager.startLocalOnlyHotspot(proxy, packageName, featureId,
+                        config);
                 if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
                     // Send message to the proxy to make sure we call back on the correct thread
                     proxy.onHotspotFailed(returnCode);
@@ -3344,6 +3355,7 @@
      *
      * @hide
      */
+    @SystemApi
     public interface SoftApCallback {
         /**
          * Called when soft AP state changes.
@@ -3381,11 +3393,11 @@
      * @hide
      */
     private class SoftApCallbackProxy extends ISoftApCallback.Stub {
-        private final Handler mHandler;
+        private final Executor mExecutor;
         private final SoftApCallback mCallback;
 
-        SoftApCallbackProxy(Looper looper, SoftApCallback callback) {
-            mHandler = new Handler(looper);
+        SoftApCallbackProxy(Executor executor, SoftApCallback callback) {
+            mExecutor = executor;
             mCallback = callback;
         }
 
@@ -3396,7 +3408,8 @@
                         + ", failureReason=" + failureReason);
             }
 
-            mHandler.post(() -> {
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
                 mCallback.onStateChanged(state, failureReason);
             });
         }
@@ -3408,7 +3421,8 @@
                         + clients.size() + " clients");
             }
 
-            mHandler.post(() -> {
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
                 mCallback.onConnectedClientsChanged(clients);
             });
         }
@@ -3418,7 +3432,9 @@
             if (mVerboseLoggingEnabled) {
                 Log.v(TAG, "SoftApCallbackProxy: onInfoChange: softApInfo=" + softApInfo);
             }
-            mHandler.post(() -> {
+
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
                 mCallback.onInfoChanged(softApInfo);
             });
         }
@@ -3437,18 +3453,19 @@
      * <p>
      *
      * @param callback Callback for soft AP events
-     * @param handler  The Handler on whose thread to execute the callbacks of the {@code callback}
-     *                 object. If null, then the application's main thread will be used.
+     * @param executor The executor to execute the callbacks of the {@code executor}
+     *                 object. If null, then the application's main executor will be used.
      *
      * @hide
      */
+    @SystemApi
     @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void registerSoftApCallback(@NonNull SoftApCallback callback,
-                                       @Nullable Handler handler) {
+                                       @Nullable @CallbackExecutor Executor executor) {
         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
-        Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", handler=" + handler);
+        Log.v(TAG, "registerSoftApCallback: callback=" + callback + ", executor=" + executor);
 
-        Looper looper = (handler == null) ? mContext.getMainLooper() : handler.getLooper();
+        executor = (executor == null) ? mContext.getMainExecutor() : executor;
         Binder binder = new Binder();
         try {
             IWifiManager iWifiManager = getIWifiManager();
@@ -3456,7 +3473,7 @@
                 throw new RemoteException("Wifi service is not running");
             }
             iWifiManager.registerSoftApCallback(
-                    binder, new SoftApCallbackProxy(looper, callback), callback.hashCode());
+                    binder, new SoftApCallbackProxy(executor, callback), callback.hashCode());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -5439,7 +5456,7 @@
             }
             iWifiManager.registerSuggestionConnectionStatusListener(new Binder(),
                     new SuggestionConnectionStatusListenerProxy(executor, listener),
-                    listener.hashCode(), mContext.getOpPackageName());
+                    listener.hashCode(), mContext.getOpPackageName(), mContext.getFeatureId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 0a99326..7e14451 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -137,7 +137,8 @@
     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
     public List<Integer> getAvailableChannels(@WifiBand int band) {
         try {
-            Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName());
+            Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
+                    mContext.getFeatureId());
             List<Integer> channels = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
             return channels == null ? new ArrayList<>() : channels;
         } catch (RemoteException e) {
@@ -220,6 +221,8 @@
     public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
     /** {@hide} */
     public static final String REQUEST_PACKAGE_NAME_KEY = "PackageName";
+    /** {@hide} */
+    public static final String REQUEST_FEATURE_ID_KEY = "FeatureId";
 
     /**
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
@@ -864,6 +867,7 @@
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
@@ -880,6 +884,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
@@ -892,6 +897,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         Message reply =
                 mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams);
         return reply.what == CMD_OP_SUCCEEDED;
@@ -929,6 +935,7 @@
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
@@ -945,6 +952,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams);
     }
 
@@ -956,6 +964,7 @@
         validateChannel();
         Bundle scanParams = new Bundle();
         scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
+        scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
         Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0,
                 scanParams);
         if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index c4b24cf..88f95ad 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -38,14 +38,15 @@
     Characteristics getCharacteristics();
 
     // client API
-    void connect(in IBinder binder, in String callingPackage, in IWifiAwareEventCallback callback,
-            in ConfigRequest configRequest, boolean notifyOnIdentityChanged);
+    void connect(in IBinder binder, in String callingPackage, in String callingFeatureId,
+            in IWifiAwareEventCallback callback, in ConfigRequest configRequest,
+            boolean notifyOnIdentityChanged);
     void disconnect(int clientId, in IBinder binder);
 
-    void publish(in String callingPackage, int clientId, in PublishConfig publishConfig,
-            in IWifiAwareDiscoverySessionCallback callback);
-    void subscribe(in String callingPackage, int clientId, in SubscribeConfig subscribeConfig,
-            in IWifiAwareDiscoverySessionCallback callback);
+    void publish(in String callingPackage, in String callingFeatureId, int clientId,
+            in PublishConfig publishConfig, in IWifiAwareDiscoverySessionCallback callback);
+    void subscribe(in String callingPackage, in String callingFeatureId, int clientId,
+            in SubscribeConfig subscribeConfig, in IWifiAwareDiscoverySessionCallback callback);
 
     // session API
     void updatePublish(int clientId, int discoverySessionId, in PublishConfig publishConfig);
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 41a412b..5aab347 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -268,7 +268,7 @@
 
             try {
                 Binder binder = new Binder();
-                mService.connect(binder, mContext.getOpPackageName(),
+                mService.connect(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
                         new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback,
                                 identityChangedListener), configRequest,
                         identityChangedListener != null);
@@ -299,7 +299,8 @@
         }
 
         try {
-            mService.publish(mContext.getOpPackageName(), clientId, publishConfig,
+            mService.publish(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+                    publishConfig,
                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
                             clientId));
         } catch (RemoteException e) {
@@ -336,7 +337,8 @@
         }
 
         try {
-            mService.subscribe(mContext.getOpPackageName(), clientId, subscribeConfig,
+            mService.subscribe(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+                    subscribeConfig,
                     new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
                             clientId));
         } catch (RemoteException e) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index fd26817b..60fe604 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -120,10 +120,12 @@
             new Creator<WifiAwareNetworkInfo>() {
                 @Override
                 public WifiAwareNetworkInfo createFromParcel(Parcel in) {
+                    byte[] addr = in.createByteArray();
+                    String interfaceName = in.readString();
+                    int port = in.readInt();
+                    int transportProtocol = in.readInt();
                     Inet6Address ipv6Addr;
                     try {
-                        byte[] addr = in.createByteArray();
-                        String interfaceName = in.readString();
                         NetworkInterface ni = null;
                         if (interfaceName != null) {
                             try {
@@ -135,11 +137,8 @@
                         ipv6Addr = Inet6Address.getByAddress(null, addr, ni);
                     } catch (UnknownHostException e) {
                         e.printStackTrace();
-                        return null;
+                        return new WifiAwareNetworkInfo(null);
                     }
-                    int port = in.readInt();
-                    int transportProtocol = in.readInt();
-
                     return new WifiAwareNetworkInfo(ipv6Addr, port, transportProtocol);
                 }
 
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 0511f24..5a4ed3c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -20,7 +20,6 @@
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.annotation.SystemApi;
 import android.net.NetworkSpecifier;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -337,7 +336,8 @@
          * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
          * is optional - if not called, then an Open (unencrypted) connection will be created.
          *
-         * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
+         * @param pskPassphrase The (optional) passphrase to be used to encrypt the link. Use the
+         *                      {@link #setPmk(byte[])} to specify a PMK.
          * @return the current {@link Builder} builder, enabling chaining of builder
          *         methods.
          */
@@ -358,9 +358,7 @@
          *            specify a Passphrase.
          * @return the current {@link Builder} builder, enabling chaining of builder
          *         methods.
-         * @hide
          */
-        @SystemApi
         public @NonNull Builder setPmk(@NonNull byte[] pmk) {
             if (!WifiAwareUtils.validatePmk(pmk)) {
                 throw new IllegalArgumentException("PMK must 32 bytes");
@@ -377,7 +375,7 @@
          * <ul>
          *     <li>The server device must be the Publisher device!
          *     <li>The port information can only be specified on secure links, specified using
-         *     {@link #setPskPassphrase(String)}.
+         *     {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])}.
          * </ul>
          *
          * @param port A positive integer indicating the port to be used for communication.
@@ -400,7 +398,7 @@
          * <ul>
          *     <li>The server device must be the Publisher device!
          *     <li>The transport protocol information can only be specified on secure links,
-         *     specified using {@link #setPskPassphrase(String)}.
+         *     specified using {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])}.
          * </ul>
          * The transport protocol number is assigned by the Internet Assigned Numbers Authority
          * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
@@ -426,7 +424,7 @@
          * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
          * <p> The default builder constructor will initialize a NetworkSpecifier which requests an
          * open (non-encrypted) link. To request an encrypted link use the
-         * {@link #setPskPassphrase(String)} builder method.
+         * {@link #setPskPassphrase(String)} or {@link #setPmk(byte[])} builder methods.
          *
          * @return A {@link NetworkSpecifier} to be used to construct
          * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index d37c4a2..3178519 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -345,6 +345,13 @@
             "android.net.wifi.p2p.CALLING_PACKAGE";
 
     /**
+     * The lookup key for a calling feature id from WifiP2pManager
+     * @hide
+     */
+    public static final String CALLING_FEATURE_ID =
+            "android.net.wifi.p2p.CALLING_FEATURE_ID";
+
+    /**
      * The lookup key for a calling package binder from WifiP2pManager
      * @hide
      */
@@ -1159,6 +1166,7 @@
                 == AsyncChannel.STATUS_SUCCESSFUL) {
             Bundle bundle = new Bundle();
             bundle.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
+            bundle.putString(CALLING_FEATURE_ID, c.mContext.getFeatureId());
             bundle.putBinder(CALLING_BINDER, binder);
             c.mAsyncChannel.sendMessage(UPDATE_CHANNEL_INFO, 0,
                     c.putListener(null), bundle);
diff --git a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
index 3e37af0..7c92a6b 100644
--- a/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
+++ b/wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl
@@ -27,7 +27,7 @@
 interface IWifiRttManager
 {
     boolean isAvailable();
-    void startRanging(in IBinder binder, in String callingPackage, in WorkSource workSource,
-            in RangingRequest request, in IRttCallback callback);
+    void startRanging(in IBinder binder, in String callingPackage, in String callingFeatureId,
+            in WorkSource workSource, in RangingRequest request, in IRttCallback callback);
     void cancelRanging(in WorkSource workSource);
 }
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index 457e904..770a120 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -146,8 +146,8 @@
 
         Binder binder = new Binder();
         try {
-            mService.startRanging(binder, mContext.getOpPackageName(), workSource, request,
-                    new IRttCallback.Stub() {
+            mService.startRanging(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
+                    workSource, request, new IRttCallback.Stub() {
                         @Override
                         public void onRangingFailure(int status) throws RemoteException {
                             clearCallingIdentity();
diff --git a/wifi/java/com/android/server/wifi/BaseWifiService.java b/wifi/java/com/android/server/wifi/BaseWifiService.java
index 671708f..cf74ff0 100644
--- a/wifi/java/com/android/server/wifi/BaseWifiService.java
+++ b/wifi/java/com/android/server/wifi/BaseWifiService.java
@@ -86,12 +86,12 @@
     }
 
     @Override
-    public ParceledListSlice getConfiguredNetworks(String packageName) {
+    public ParceledListSlice getConfiguredNetworks(String packageName, String featureId) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName) {
+    public ParceledListSlice getPrivilegedConfiguredNetworks(String packageName, String featureId) {
         throw new UnsupportedOperationException();
     }
 
@@ -175,12 +175,12 @@
     }
 
     @Override
-    public boolean startScan(String packageName) {
+    public boolean startScan(String packageName, String featureId) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public List<ScanResult> getScanResults(String callingPackage) {
+    public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
         throw new UnsupportedOperationException();
     }
 
@@ -200,7 +200,7 @@
     }
 
     @Override
-    public WifiInfo getConnectionInfo(String callingPackage) {
+    public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) {
         throw new UnsupportedOperationException();
     }
 
@@ -289,21 +289,9 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @deprecated replaced by {@link #startLocalOnlyHotspot(ILocalOnlyHotspotCallback, String)} */
-    @Deprecated
-    public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** @deprecated replaced by newer signature */
-    @Deprecated
-    public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName) {
-        return startLocalOnlyHotspot(callback, packageName, null);
-    }
-
     @Override
     public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
-            SoftApConfiguration customConfig) {
+            String featureId, SoftApConfiguration customConfig) {
         throw new UnsupportedOperationException();
     }
 
@@ -312,12 +300,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /** @deprecated replaced by {@link #startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback)} */
-    @Deprecated
-    public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
         throw new UnsupportedOperationException();
@@ -449,7 +431,8 @@
 
     @Override
     public int addNetworkSuggestions(
-            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
+            List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
+            String callingFeatureId) {
         throw new UnsupportedOperationException();
     }
 
@@ -545,7 +528,7 @@
     @Override
     public void registerSuggestionConnectionStatusListener(IBinder binder,
             ISuggestionConnectionStatusListener listener,
-            int listenerIdentifier, String packageName) {
+            int listenerIdentifier, String packageName, String featureId) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index a78cca3..17f3bb2 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -34,6 +34,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyInt;
 import static org.mockito.Mockito.anyList;
@@ -66,6 +67,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
@@ -96,6 +98,7 @@
     private static final int TEST_UID = 14553;
     private static final int TEST_NETWORK_ID = 143;
     private static final String TEST_PACKAGE_NAME = "TestPackage";
+    private static final String TEST_FEATURE_ID = "TestFeature";
     private static final String TEST_COUNTRY_CODE = "US";
     private static final String[] TEST_MAC_ADDRESSES = {"da:a1:19:0:0:0"};
     private static final int TEST_AP_FREQUENCY = 2412;
@@ -177,8 +180,8 @@
     @Test
     public void testCreationAndCloseOfLocalOnlyHotspotReservation() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
@@ -195,8 +198,8 @@
     public void testLocalOnlyHotspotReservationCallsStopProperlyInTryWithResources()
             throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
         callback.onStarted(mWifiManager.new LocalOnlyHotspotReservation(mApConfig));
@@ -355,8 +358,8 @@
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
 
-        verify(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
+        verify(mWifiService).startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
+                anyString(), nullable(String.class), eq(null));
     }
 
     /**
@@ -366,8 +369,9 @@
     @Test(expected = SecurityException.class)
     public void testStartLocalOnlyHotspotThrowsSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
+        doThrow(new SecurityException()).when(mWifiService).startLocalOnlyHotspot(
+                any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+                eq(null));
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -378,8 +382,9 @@
     @Test(expected = IllegalStateException.class)
     public void testStartLocalOnlyHotspotThrowsIllegalStateException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        doThrow(new IllegalStateException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
+        doThrow(new IllegalStateException()).when(mWifiService).startLocalOnlyHotspot(
+                any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+                eq(null));
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
     }
 
@@ -389,8 +394,8 @@
     @Test
     public void testCorrectLooperIsUsedForHandler() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -408,8 +413,8 @@
         TestLooper altLooper = new TestLooper();
         when(mContext.getMainExecutor()).thenReturn(altLooper.getNewExecutor());
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, null);
         altLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -428,8 +433,8 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
-                .thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
@@ -454,8 +459,8 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
-                .thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
@@ -479,8 +484,8 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
-                .thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
@@ -502,8 +507,8 @@
         Handler callbackHandler = new Handler(callbackLooper.getLooper());
         ArgumentCaptor<ILocalOnlyHotspotCallback> internalCallback =
                 ArgumentCaptor.forClass(ILocalOnlyHotspotCallback.class);
-        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(), eq(null)))
-                .thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(internalCallback.capture(), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, callbackHandler);
         callbackLooper.dispatchAll();
         mLooper.dispatchAll();
@@ -521,8 +526,8 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -537,8 +542,8 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(ERROR_TETHERING_DISALLOWED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(ERROR_TETHERING_DISALLOWED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
@@ -554,8 +559,9 @@
     @Test(expected = SecurityException.class)
     public void testLocalOnlyHotspotCallbackFullOnSecurityException() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        doThrow(new SecurityException()).when(mWifiService)
-                .startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(), eq(null));
+        doThrow(new SecurityException()).when(mWifiService).startLocalOnlyHotspot(
+                any(ILocalOnlyHotspotCallback.class), anyString(), nullable(String.class),
+                eq(null));
         try {
             mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         } catch (SecurityException e) {
@@ -575,8 +581,8 @@
     @Test
     public void testLocalOnlyHotspotCallbackFullOnNoChannelError() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         //assertEquals(ERROR_NO_CHANNEL, callback.mFailureReason);
@@ -591,8 +597,8 @@
     @Test
     public void testCancelLocalOnlyHotspotRequestCallsStopOnWifiService() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
         verify(mWifiService).stopLocalOnlyHotspot();
@@ -613,8 +619,8 @@
     @Test
     public void testCallbackAfterLocalOnlyHotspotWasCancelled() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(REQUEST_REGISTERED);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(REQUEST_REGISTERED);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mWifiManager.cancelLocalOnlyHotspotRequest();
         verify(mWifiService).stopLocalOnlyHotspot();
@@ -632,8 +638,8 @@
     @Test
     public void testCancelAfterLocalOnlyHotspotCallbackTriggered() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
-        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
-                anyString(), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
+        when(mWifiService.startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class), anyString(),
+                nullable(String.class), eq(null))).thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
@@ -651,8 +657,8 @@
                 .build();
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         mWifiManager.startLocalOnlyHotspot(customConfig, mExecutor, callback);
-        verify(mWifiService).startLocalOnlyHotspot(
-                any(ILocalOnlyHotspotCallback.class), anyString(), eq(customConfig));
+        verify(mWifiService).startLocalOnlyHotspot(any(ILocalOnlyHotspotCallback.class),
+                anyString(), nullable(String.class), eq(customConfig));
     }
 
     /**
@@ -696,7 +702,7 @@
     @Test
     public void registerSoftApCallbackThrowsIllegalArgumentExceptionOnNullArgumentForCallback() {
         try {
-            mWifiManager.registerSoftApCallback(null, mHandler);
+            mWifiManager.registerSoftApCallback(null, new HandlerExecutor(mHandler));
             fail("expected IllegalArgumentException");
         } catch (IllegalArgumentException expected) {
         }
@@ -721,7 +727,7 @@
     public void registerSoftApCallbackUsesMainLooperOnNullArgumentForHandler() {
         when(mContext.getMainLooper()).thenReturn(mLooper.getLooper());
         mWifiManager.registerSoftApCallback(mSoftApCallback, null);
-        verify(mContext).getMainLooper();
+        verify(mContext).getMainExecutor();
     }
 
     /**
@@ -729,7 +735,7 @@
      */
     @Test
     public void registerSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), anyInt());
     }
@@ -740,7 +746,7 @@
     @Test
     public void unregisterSoftApCallbackCallGoesToWifiServiceImpl() throws Exception {
         ArgumentCaptor<Integer> callbackIdentifier = ArgumentCaptor.forClass(Integer.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), callbackIdentifier.capture());
 
@@ -755,7 +761,7 @@
     public void softApCallbackProxyCallsOnStateChanged() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -771,7 +777,7 @@
     public void softApCallbackProxyCallsOnConnectedClientsChanged() throws Exception {
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -792,7 +798,7 @@
         testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -811,7 +817,7 @@
         testSoftApInfo.setBandwidth(TEST_AP_BANDWIDTH);
         ArgumentCaptor<ISoftApCallback.Stub> callbackCaptor =
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -837,7 +843,7 @@
                 ArgumentCaptor.forClass(ISoftApCallback.Stub.class);
         TestLooper altLooper = new TestLooper();
         Handler altHandler = new Handler(altLooper.getLooper());
-        mWifiManager.registerSoftApCallback(mSoftApCallback, altHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(altHandler));
         verify(mWifiService).registerSoftApCallback(any(IBinder.class), callbackCaptor.capture(),
                 anyInt());
 
@@ -851,7 +857,7 @@
      */
     @Test
     public void testCorrectLooperIsUsedForSoftApCallbackHandler() throws Exception {
-        mWifiManager.registerSoftApCallback(mSoftApCallback, mHandler);
+        mWifiManager.registerSoftApCallback(mSoftApCallback, new HandlerExecutor(mHandler));
         mLooper.dispatchAll();
         verify(mWifiService).registerSoftApCallback(any(IBinder.class),
                 any(ISoftApCallback.Stub.class), anyInt());
@@ -1126,10 +1132,12 @@
      */
     @Test
     public void testStartScan() throws Exception {
-        when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(true);
+        when(mWifiService.startScan(eq(TEST_PACKAGE_NAME), nullable(String.class))).thenReturn(
+                true);
         assertTrue(mWifiManager.startScan());
 
-        when(mWifiService.startScan(TEST_PACKAGE_NAME)).thenReturn(false);
+        when(mWifiService.startScan(eq(TEST_PACKAGE_NAME), nullable(String.class))).thenReturn(
+                false);
         assertFalse(mWifiManager.startScan());
     }
 
@@ -1335,16 +1343,17 @@
     @Test
     public void addGetRemoveNetworkSuggestions() throws Exception {
         List<WifiNetworkSuggestion> testList = new ArrayList<>();
-        when(mWifiService.addNetworkSuggestions(any(List.class), anyString()))
-                .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
-        when(mWifiService.removeNetworkSuggestions(any(List.class), anyString()))
-                .thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+        when(mWifiService.addNetworkSuggestions(any(List.class), anyString(),
+                nullable(String.class))).thenReturn(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
+        when(mWifiService.removeNetworkSuggestions(any(List.class), anyString())).thenReturn(
+                WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS);
         when(mWifiService.getNetworkSuggestions(anyString()))
                 .thenReturn(testList);
 
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiManager.addNetworkSuggestions(testList));
-        verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME));
+        verify(mWifiService).addNetworkSuggestions(anyList(), eq(TEST_PACKAGE_NAME),
+                nullable(String.class));
 
         assertEquals(testList, mWifiManager.getNetworkSuggestions());
         verify(mWifiService).getNetworkSuggestions(eq(TEST_PACKAGE_NAME));
@@ -1604,7 +1613,8 @@
     @Test
     public void testGetConnectionInfo() throws Exception {
         WifiInfo wifiInfo = new WifiInfo();
-        when(mWifiService.getConnectionInfo(anyString())).thenReturn(wifiInfo);
+        when(mWifiService.getConnectionInfo(anyString(), nullable(String.class))).thenReturn(
+                wifiInfo);
 
         assertEquals(wifiInfo, mWifiManager.getConnectionInfo());
     }
@@ -1835,7 +1845,7 @@
         Executor executor = new SynchronousExecutor();
         mWifiManager.addSuggestionConnectionStatusListener(executor, mListener);
         verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
-                callbackCaptor.capture(), anyInt(), anyString());
+                callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
         callbackCaptor.getValue().onConnectionStatus(mWifiNetworkSuggestion, errorCode);
         verify(mListener).onConnectionStatus(any(WifiNetworkSuggestion.class), eq(errorCode));
     }
@@ -1850,7 +1860,7 @@
                 ArgumentCaptor.forClass(ISuggestionConnectionStatusListener.Stub.class);
         mWifiManager.addSuggestionConnectionStatusListener(mExecutor, mListener);
         verify(mWifiService).registerSuggestionConnectionStatusListener(any(IBinder.class),
-                callbackCaptor.capture(), anyInt(), anyString());
+                callbackCaptor.capture(), anyInt(), anyString(), nullable(String.class));
         callbackCaptor.getValue().onConnectionStatus(any(WifiNetworkSuggestion.class), errorCode);
         verify(mExecutor).execute(any(Runnable.class));
     }
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index ea136d6..f4fa38b 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -267,6 +267,8 @@
         assertNull(messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY));
         assertEquals(mContext.getOpPackageName(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
+        assertEquals(mContext.getFeatureId(),
+                messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
 
     }
 
@@ -295,7 +297,8 @@
         Bundle messageBundle = (Bundle) message.obj;
         assertEquals(mContext.getOpPackageName(),
                 messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
-
+        assertEquals(mContext.getFeatureId(),
+                messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
     }
 
     /**
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index db8220b..3483ff8 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -168,7 +168,7 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), any(),
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(),
                 clientProxyCallback.capture(), isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -178,7 +178,8 @@
         // (2) publish - should succeed
         PublishConfig publishConfig = new PublishConfig.Builder().build();
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig), any());
+        inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
+                any());
 
         // (3) disconnect
         session.close();
@@ -190,7 +191,7 @@
 
         // (5) connect
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), isNull(),
+        inOrder.verify(mockAwareService).connect(binder.capture(), any(), any(), any(), isNull(),
                 eq(false));
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
@@ -212,7 +213,7 @@
 
         // (1) connect + failure
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 isNull(), eq(false));
         clientProxyCallback.getValue().onConnectFail(reason);
         mMockLooper.dispatchAll();
@@ -220,7 +221,7 @@
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -230,7 +231,8 @@
         // (4) subscribe: should succeed
         SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().build();
         session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig), any());
+        inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
+                any());
 
         verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService);
     }
@@ -249,7 +251,7 @@
 
         // (1) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -257,7 +259,7 @@
 
         // (2) connect + success
         mDut.attach(mockCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 isNull(), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId + 1);
         mMockLooper.dispatchAll();
@@ -304,7 +306,7 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -313,7 +315,7 @@
 
         // (1) publish
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+        inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
 
         // (2) publish session created
@@ -396,7 +398,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -405,7 +407,7 @@
 
         // (2) publish: successfully - then terminated
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+        inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
         sessionProxyCallback.getValue().onSessionTerminated(0);
@@ -453,7 +455,7 @@
 
         // (0) connect + success
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -462,7 +464,7 @@
 
         // (1) subscribe
         session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
+        inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
                 sessionProxyCallback.capture());
 
         // (2) subscribe session created
@@ -538,7 +540,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -547,7 +549,7 @@
 
         // (2) subscribe: successfully - then terminated
         session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
+        inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId), eq(subscribeConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
         sessionProxyCallback.getValue().onSessionTerminated(0);
@@ -942,7 +944,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -951,7 +953,7 @@
 
         // (2) publish successfully
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+        inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
         mMockLooper.dispatchAll();
@@ -1055,7 +1057,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -1239,7 +1241,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -1248,7 +1250,7 @@
 
         // (2) publish successfully
         session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-        inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+        inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
                 sessionProxyCallback.capture());
         sessionProxyCallback.getValue().onSessionStarted(sessionId);
         mMockLooper.dispatchAll();
@@ -1474,7 +1476,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -1514,7 +1516,7 @@
 
         // (1) connect successfully
         mDut.attach(mMockLooperHandler, configRequest, mockCallback, null);
-        inOrder.verify(mockAwareService).connect(any(), any(), clientProxyCallback.capture(),
+        inOrder.verify(mockAwareService).connect(any(), any(), any(), clientProxyCallback.capture(),
                 eq(configRequest), eq(false));
         clientProxyCallback.getValue().onConnectSuccess(clientId);
         mMockLooper.dispatchAll();
@@ -1524,7 +1526,7 @@
         if (isPublish) {
             // (2) publish successfully
             session.publish(publishConfig, mockSessionCallback, mMockLooperHandler);
-            inOrder.verify(mockAwareService).publish(any(), eq(clientId), eq(publishConfig),
+            inOrder.verify(mockAwareService).publish(any(), any(), eq(clientId), eq(publishConfig),
                     sessionProxyCallback.capture());
             sessionProxyCallback.getValue().onSessionStarted(sessionId);
             mMockLooper.dispatchAll();
@@ -1533,8 +1535,8 @@
         } else {
             // (2) subscribe successfully
             session.subscribe(subscribeConfig, mockSessionCallback, mMockLooperHandler);
-            inOrder.verify(mockAwareService).subscribe(any(), eq(clientId), eq(subscribeConfig),
-                    sessionProxyCallback.capture());
+            inOrder.verify(mockAwareService).subscribe(any(), any(), eq(clientId),
+                    eq(subscribeConfig), sessionProxyCallback.capture());
             sessionProxyCallback.getValue().onSessionStarted(sessionId);
             mMockLooper.dispatchAll();
             inOrder.verify(mockSessionCallback).onSubscribeStarted(subscribeSession.capture());
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index 53bd837..a9dcde0 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -54,6 +54,7 @@
     private Executor mMockLooperExecutor;
 
     private final String packageName = "some.package.name.for.rtt.app";
+    private final String featureId = "some.feature.id.in.rtt.app";
 
     @Mock
     public Context mockContext;
@@ -70,6 +71,7 @@
         mMockLooperExecutor = mMockLooper.getNewExecutor();
 
         when(mockContext.getOpPackageName()).thenReturn(packageName);
+        when(mockContext.getFeatureId()).thenReturn(featureId);
     }
 
     /**
@@ -87,8 +89,8 @@
 
         // verify ranging request passed to service
         mDut.startRanging(request, mMockLooperExecutor, callbackMock);
-        verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
-                eq(request), callbackCaptor.capture());
+        verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(featureId),
+                eq(null),  eq(request), callbackCaptor.capture());
 
         // service calls back with success
         callbackCaptor.getValue().onRangingResults(results);
@@ -111,8 +113,8 @@
 
         // verify ranging request passed to service
         mDut.startRanging(request, mMockLooperExecutor, callbackMock);
-        verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(null),
-                eq(request), callbackCaptor.capture());
+        verify(mockRttService).startRanging(any(IBinder.class), eq(packageName), eq(featureId),
+                eq(null), eq(request), callbackCaptor.capture());
 
         // service calls back with failure code
         callbackCaptor.getValue().onRangingFailure(failureCode);